PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Operations/IListOfByteOps.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1342 lines | 1208 code | 95 blank | 39 comment | 184 complexity | d17a8f209b3ae7a6e15614ebc29afef4 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Text;
  20. using Microsoft.Scripting.Runtime;
  21. using Microsoft.Scripting.Utils;
  22. namespace IronPython.Runtime.Operations {
  23. internal static class IListOfByteOps {
  24. internal static int Compare(this IList<byte>/*!*/ self, IList<byte>/*!*/ other) {
  25. for (int i = 0; i < self.Count && i < other.Count; i++) {
  26. if (self[i] != other[i]) {
  27. if (self[i] > other[i]) {
  28. return 1;
  29. } else {
  30. return -1;
  31. }
  32. }
  33. }
  34. if (self.Count == other.Count) {
  35. return 0;
  36. }
  37. return self.Count > other.Count ? +1 : -1;
  38. }
  39. internal static int Compare(this IList<byte>/*!*/ self, string other) {
  40. for (int i = 0; i < self.Count && i < other.Length; i++) {
  41. if ((char)self[i] != other[i]) {
  42. if ((char)self[i] > other[i]) {
  43. return 1;
  44. } else {
  45. return -1;
  46. }
  47. }
  48. }
  49. if (self.Count == other.Length) {
  50. return 0;
  51. }
  52. return self.Count > other.Length ? +1 : -1;
  53. }
  54. internal static bool EndsWith(this IList<byte>/*!*/ self, IList<byte>/*!*/ suffix) {
  55. if (self.Count < suffix.Count) {
  56. return false;
  57. }
  58. int offset = self.Count - suffix.Count;
  59. for (int i = 0; i < suffix.Count; i++) {
  60. if (suffix[i] != self[i + offset]) {
  61. return false;
  62. }
  63. }
  64. return true;
  65. }
  66. internal static bool EndsWith(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ suffix, int start) {
  67. int len = bytes.Count;
  68. if (start > len) return false;
  69. // map the negative indice to its positive counterpart
  70. if (start < 0) {
  71. start += len;
  72. if (start < 0) start = 0;
  73. }
  74. return bytes.Substring(start).EndsWith(suffix);
  75. }
  76. // With optional start, test beginning at that position (the char at that index is
  77. // included in the test). With optional end, stop comparing at that position (the
  78. // char at that index is not included in the test)
  79. internal static bool EndsWith(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ suffix, int start, int end) {
  80. int len = bytes.Count;
  81. if (start > len) return false;
  82. // map the negative indices to their positive counterparts
  83. else if (start < 0) {
  84. start += len;
  85. if (start < 0) start = 0;
  86. }
  87. if (end >= len) {
  88. return bytes.Substring(start).EndsWith(suffix);
  89. } else if (end < 0) {
  90. end += len;
  91. if (end < 0) {
  92. return false;
  93. }
  94. }
  95. if (end < start) {
  96. return false;
  97. }
  98. return bytes.Substring(start, end - start).EndsWith(suffix);
  99. }
  100. internal static bool EndsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ suffix) {
  101. foreach (object obj in suffix) {
  102. if (bytes.EndsWith(ByteOps.CoerceBytes(obj))) {
  103. return true;
  104. }
  105. }
  106. return false;
  107. }
  108. internal static bool EndsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ suffix, int start) {
  109. int len = bytes.Count;
  110. if (start > len) return false;
  111. // map the negative indice to its positive counterpart
  112. if (start < 0) {
  113. start += len;
  114. if (start < 0) {
  115. start = 0;
  116. }
  117. }
  118. foreach (object obj in suffix) {
  119. if (bytes.Substring(start).EndsWith(ByteOps.CoerceBytes(obj))) {
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. internal static bool EndsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ suffix, int start, int end) {
  126. int len = bytes.Count;
  127. if (start > len) return false;
  128. // map the negative indices to their positive counterparts
  129. else if (start < 0) {
  130. start += len;
  131. if (start < 0) {
  132. start = 0;
  133. }
  134. }
  135. if (end >= len) {
  136. end = len;
  137. } else if (end < 0) {
  138. end += len;
  139. if (end < 0) {
  140. return false;
  141. }
  142. }
  143. if (end < start) {
  144. return false;
  145. }
  146. foreach (object obj in suffix) {
  147. if (bytes.Substring(start, end - start).EndsWith(ByteOps.CoerceBytes(obj))) {
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. internal static bool StartsWith(this IList<byte>/*!*/ self, IList<byte>/*!*/ prefix) {
  154. if (self.Count < prefix.Count) {
  155. return false;
  156. }
  157. for (int i = 0; i < prefix.Count; i++) {
  158. if (prefix[i] != self[i]) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. internal static int IndexOfAny(this IList<byte>/*!*/ str, IList<byte>/*!*/ separators, int i) {
  165. for (; i < str.Count; i++) {
  166. for (int j = 0; j < separators.Count; j++) {
  167. if (str[i] == separators[j]) {
  168. return i;
  169. }
  170. }
  171. }
  172. return -1;
  173. }
  174. internal static int IndexOf(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sub, int start) {
  175. return IndexOf(bytes, sub, start, bytes.Count - start);
  176. }
  177. internal static int IndexOf(this IList<byte>/*!*/ self, IList<byte>/*!*/ ssub, int start, int length) {
  178. if (ssub == null) {
  179. throw PythonOps.TypeError("cannot do None in bytes or bytearray");
  180. } else if (ssub.Count == 0) {
  181. return 0;
  182. }
  183. byte firstByte = ssub[0];
  184. for (int i = start; i < start + length; i++) {
  185. if (self[i] == firstByte) {
  186. bool differ = false;
  187. for (int j = 1; j < ssub.Count; j++) {
  188. if (j + i == start + length || ssub[j] != self[i + j]) {
  189. differ = true;
  190. break;
  191. }
  192. }
  193. if (!differ) {
  194. return i;
  195. }
  196. }
  197. }
  198. return -1;
  199. }
  200. internal static bool IsTitle(this IList<byte>/*!*/ bytes) {
  201. if (bytes.Count == 0) {
  202. return false;
  203. }
  204. bool prevCharCased = false, currCharCased = false, containsUpper = false;
  205. for (int i = 0; i < bytes.Count; i++) {
  206. if (bytes[i].IsUpper()) {
  207. containsUpper = true;
  208. if (prevCharCased)
  209. return false;
  210. else
  211. currCharCased = true;
  212. } else if (bytes[i].IsLower())
  213. if (!prevCharCased)
  214. return false;
  215. else
  216. currCharCased = true;
  217. else
  218. currCharCased = false;
  219. prevCharCased = currCharCased;
  220. }
  221. // if we've gone through the whole string and haven't encountered any rule
  222. // violations but also haven't seen an Uppercased char, then this is not a
  223. // title e.g. '\n', all whitespace etc.
  224. return containsUpper;
  225. }
  226. internal static bool IsUpper(this IList<byte>/*!*/ bytes) {
  227. bool foundUpper = false;
  228. foreach (byte b in bytes) {
  229. foundUpper = foundUpper || b.IsUpper();
  230. if (b.IsLower()) {
  231. return false;
  232. }
  233. }
  234. return foundUpper;
  235. }
  236. internal static List<byte> Title(this IList<byte>/*!*/ self) {
  237. if (self.Count == 0) {
  238. return null;
  239. }
  240. List<byte> retchars = new List<byte>(self);
  241. bool prevCharCased = false;
  242. bool currCharCased = false;
  243. int i = 0;
  244. do {
  245. if (retchars[i].IsUpper() || retchars[i].IsLower()) {
  246. if (!prevCharCased)
  247. retchars[i] = retchars[i].ToUpper();
  248. else
  249. retchars[i] = retchars[i].ToLower();
  250. currCharCased = true;
  251. } else {
  252. currCharCased = false;
  253. }
  254. i++;
  255. prevCharCased = currCharCased;
  256. } while (i < retchars.Count);
  257. return retchars;
  258. }
  259. internal static int LastIndexOf(this IList<byte>/*!*/ self, IList<byte>/*!*/ sub, int start, int length) {
  260. byte firstByte = sub[sub.Count - 1];
  261. for (int i = start - 1; i >= start - length; i--) {
  262. if (self[i] == firstByte) {
  263. bool differ = false;
  264. if (sub.Count != 1) {
  265. for (int j = sub.Count - 2, selfIndex = 1; j >= 0; j--, selfIndex++) {
  266. if (sub[j] != self[i - selfIndex]) {
  267. differ = true;
  268. break;
  269. }
  270. }
  271. }
  272. if (!differ) {
  273. return i - sub.Count + 1;
  274. }
  275. }
  276. }
  277. return -1;
  278. }
  279. internal static List<byte>/*!*/[]/*!*/ Split(this IList<byte>/*!*/ str, IList<byte>/*!*/ separators, int maxComponents, StringSplitOptions options) {
  280. ContractUtils.RequiresNotNull(str, "str");
  281. bool keep_empty = (options & StringSplitOptions.RemoveEmptyEntries) != StringSplitOptions.RemoveEmptyEntries;
  282. if (separators == null) {
  283. Debug.Assert(!keep_empty);
  284. return SplitOnWhiteSpace(str, maxComponents);
  285. }
  286. List<List<byte>> result = new List<List<byte>>(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1);
  287. int i = 0;
  288. int next;
  289. while (maxComponents > 1 && i < str.Count && (next = IndexOfAny(str, separators, i)) != -1) {
  290. if (next > i || keep_empty) {
  291. result.Add(Substring(str, i, next - i));
  292. maxComponents--;
  293. }
  294. i = next + separators.Count;
  295. }
  296. if (i < str.Count || keep_empty) {
  297. /*while (i < str.Count) {
  298. if (!separators.Contains(str[i])) {
  299. break;
  300. }
  301. i++;
  302. }*/
  303. result.Add(Substring(str, i));
  304. }
  305. return result.ToArray();
  306. }
  307. internal static List<byte>/*!*/[]/*!*/ SplitOnWhiteSpace(this IList<byte>/*!*/ str, int maxComponents) {
  308. ContractUtils.RequiresNotNull(str, "str");
  309. List<List<byte>> result = new List<List<byte>>(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1);
  310. int i = 0;
  311. int next;
  312. while (maxComponents > 1 && i < str.Count && (next = IndexOfWhiteSpace(str, i)) != -1) {
  313. if (next > i) {
  314. result.Add(Substring(str, i, next - i));
  315. maxComponents--;
  316. }
  317. i = next + 1;
  318. }
  319. if (i < str.Count) {
  320. // check if we only have white space remaining
  321. while (i < str.Count) {
  322. if (!str[i].IsWhiteSpace()) {
  323. break;
  324. }
  325. i++;
  326. }
  327. if (i < str.Count) {
  328. result.Add(Substring(str, i));
  329. }
  330. }
  331. return result.ToArray();
  332. }
  333. internal static bool StartsWith(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ prefix, int start, int end) {
  334. int len = bytes.Count;
  335. if (start > len) {
  336. return false;
  337. } else if (start < 0) {
  338. // map the negative indices to their positive counterparts
  339. start += len;
  340. if (start < 0) {
  341. start = 0;
  342. }
  343. }
  344. if (end >= len) {
  345. return bytes.Substring(start).StartsWith(prefix);
  346. } else if (end < 0) {
  347. end += len;
  348. if (end < 0) {
  349. return false;
  350. }
  351. }
  352. if (end < start) {
  353. return false;
  354. }
  355. return bytes.Substring(start, end - start).StartsWith(prefix);
  356. }
  357. internal static List<byte>/*!*/ Replace(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ old, IList<byte>/*!*/ new_, int maxsplit) {
  358. if (new_ == null) {
  359. throw PythonOps.TypeError("expected bytes or bytearray, got NoneType");
  360. }
  361. if (maxsplit == -1) {
  362. maxsplit = old.Count + 1;
  363. }
  364. if (old.Count == 0) {
  365. return ReplaceEmpty(bytes, new_, maxsplit);
  366. }
  367. List<byte> ret = new List<byte>(bytes.Count);
  368. int index;
  369. int start = 0;
  370. while (maxsplit > 0 && (index = bytes.IndexOf(old, start)) != -1) {
  371. ret.AddRange(bytes.Substring(start, index - start));
  372. ret.AddRange(new_);
  373. start = index + old.Count;
  374. maxsplit--;
  375. }
  376. ret.AddRange(bytes.Substring(start));
  377. return ret;
  378. }
  379. private static List<byte>/*!*/ ReplaceEmpty(this IList<byte>/*!*/ self, IList<byte>/*!*/ new_, int maxsplit) {
  380. int max = maxsplit > self.Count ? self.Count : maxsplit;
  381. List<byte> ret = new List<byte>(self.Count * (new_.Count + 1));
  382. for (int i = 0; i < max; i++) {
  383. ret.AddRange(new_);
  384. ret.Add(self[i]);
  385. }
  386. for (int i = max; i < self.Count; i++) {
  387. ret.Add(self[i]);
  388. }
  389. if (maxsplit > max) {
  390. ret.AddRange(new_);
  391. }
  392. return ret;
  393. }
  394. internal static int ReverseFind(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sub, int? start, int? end) {
  395. if (sub == null) {
  396. throw PythonOps.TypeError("expected string, got NoneType");
  397. } else if (start > bytes.Count) {
  398. return -1;
  399. }
  400. int iStart, iEnd;
  401. iStart = FixStart(bytes, start);
  402. iEnd = FixEnd(bytes, end);
  403. if (iStart > iEnd) {
  404. // can't possibly match anything, not even an empty string
  405. return -1;
  406. } else if (sub.Count == 0) {
  407. // match at the end
  408. return iEnd;
  409. } else if (end == 0) {
  410. // can't possibly find anything
  411. return -1;
  412. }
  413. return bytes.LastIndexOf(sub, iEnd, iEnd - iStart);
  414. }
  415. internal static List/*!*/ RightSplit(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sep, int maxsplit, Func<IList<byte>/*!*/, IList<byte>>/*!*/ ctor) {
  416. // rsplit works like split but needs to split from the right;
  417. // reverse the original string (and the sep), split, reverse
  418. // the split list and finally reverse each element of the list
  419. IList<byte> reversed = bytes.ReverseBytes();
  420. if (sep != null) {
  421. sep = sep.ReverseBytes();
  422. }
  423. List temp = null, ret = null;
  424. temp = ctor(reversed).Split(sep, maxsplit, x => ctor(x));
  425. temp.reverse();
  426. int resultlen = temp.__len__();
  427. if (resultlen != 0) {
  428. ret = new List(resultlen);
  429. foreach (IList<byte> s in temp)
  430. ret.AddNoLock(ctor(s.ReverseBytes()));
  431. } else {
  432. ret = temp;
  433. }
  434. return ret;
  435. }
  436. internal static int IndexOfWhiteSpace(this IList<byte>/*!*/ str, int start) {
  437. while (start < str.Count && !str[start].IsWhiteSpace()) start++;
  438. return (start == str.Count) ? -1 : start;
  439. }
  440. internal static byte[]/*!*/ ReverseBytes(this IList<byte>/*!*/ s) {
  441. byte[] rchars = new byte[s.Count];
  442. for (int i = s.Count - 1, j = 0; i >= 0; i--, j++) {
  443. rchars[j] = s[i];
  444. }
  445. return rchars;
  446. }
  447. internal static List<byte>/*!*/ Substring(this IList<byte>/*!*/ bytes, int start) {
  448. return Substring(bytes, start, bytes.Count - start);
  449. }
  450. internal static List<byte>/*!*/ Substring(this IList<byte>/*!*/ bytes, int start, int len) {
  451. List<byte> substr = new List<byte>();
  452. for (int i = start; i < start + len; i++) {
  453. substr.Add(bytes[i]);
  454. }
  455. return substr;
  456. }
  457. internal static List<byte>/*!*/ Multiply(this IList<byte>/*!*/ self, int count) {
  458. if (count <= 0) {
  459. return new List<byte>();
  460. }
  461. List<byte> res = new List<byte>(checked(self.Count * count));
  462. for (int i = 0; i < count; i++) {
  463. res.AddRange(self);
  464. }
  465. return res;
  466. }
  467. internal static List<byte>/*!*/ Capitalize(this IList<byte>/*!*/ bytes) {
  468. List<byte> res = new List<byte>(bytes);
  469. if (res.Count > 0) {
  470. res[0] = res[0].ToUpper();
  471. for (int i = 1; i < res.Count; i++) {
  472. res[i] = res[i].ToLower();
  473. }
  474. }
  475. return res;
  476. }
  477. internal static List<byte> TryCenter(this IList<byte>/*!*/ bytes, int width, int fillchar) {
  478. int spaces = width - bytes.Count;
  479. if (spaces <= 0) {
  480. return null;
  481. }
  482. byte fill = fillchar.ToByteChecked();
  483. List<byte> newBytes = new List<byte>();
  484. for (int i = 0; i < spaces / 2; i++) {
  485. newBytes.Add(fill);
  486. }
  487. newBytes.AddRange(bytes);
  488. for (int i = 0; i < (spaces + 1) / 2; i++) {
  489. newBytes.Add(fill);
  490. }
  491. return newBytes;
  492. }
  493. internal static int CountOf(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ ssub, int start, int end) {
  494. if (ssub == null) {
  495. throw PythonOps.TypeError("expected bytes or byte array, got NoneType");
  496. }
  497. if (start > bytes.Count) {
  498. return 0;
  499. }
  500. start = PythonOps.FixSliceIndex(start, bytes.Count);
  501. end = PythonOps.FixSliceIndex(end, bytes.Count);
  502. if (ssub.Count == 0) {
  503. return Math.Max((end - start) + 1, 0);
  504. }
  505. int count = 0;
  506. while (true) {
  507. if (end <= start) break;
  508. int index = bytes.IndexOf(ssub, start, end - start);
  509. if (index == -1) break;
  510. count++;
  511. start = index + ssub.Count;
  512. }
  513. return count;
  514. }
  515. internal static List<byte>/*!*/ ExpandTabs(this IList<byte>/*!*/ bytes, int tabsize) {
  516. List<byte> ret = new List<byte>(bytes.Count * 2);
  517. int col = 0;
  518. for (int i = 0; i < bytes.Count; i++) {
  519. byte ch = bytes[i];
  520. switch (ch) {
  521. case (byte)'\n':
  522. case (byte)'\r': col = 0; ret.Add(ch); break;
  523. case (byte)'\t':
  524. if (tabsize > 0) {
  525. int tabs = tabsize - (col % tabsize);
  526. int existingSize = ret.Capacity;
  527. ret.Capacity = checked(existingSize + tabs);
  528. for (int j = 0; j < tabs; j++) {
  529. ret.Add((byte)' ');
  530. }
  531. col = 0;
  532. }
  533. break;
  534. default:
  535. col++;
  536. ret.Add(ch);
  537. break;
  538. }
  539. }
  540. return ret;
  541. }
  542. internal static int IndexOfByte(this IList<byte>/*!*/ bytes, int item, int start, int stop) {
  543. start = PythonOps.FixSliceIndex(start, bytes.Count);
  544. stop = PythonOps.FixSliceIndex(stop, bytes.Count);
  545. for (int i = start; i < Math.Min(stop, bytes.Count); i++) {
  546. if (bytes[i] == item) {
  547. return i;
  548. }
  549. }
  550. throw PythonOps.ValueError("bytearray.index(item): item not in bytearray");
  551. }
  552. internal static string/*!*/ BytesRepr(this IList<byte>/*!*/ bytes) {
  553. StringBuilder res = new StringBuilder();
  554. res.Append("b'");
  555. for (int i = 0; i < bytes.Count; i++) {
  556. byte ch = bytes[i];
  557. switch (ch) {
  558. case (byte)'\\': res.Append("\\\\"); break;
  559. case (byte)'\t': res.Append("\\t"); break;
  560. case (byte)'\n': res.Append("\\n"); break;
  561. case (byte)'\r': res.Append("\\r"); break;
  562. case (byte)'\'':
  563. res.Append('\\');
  564. res.Append('\'');
  565. break;
  566. default:
  567. if (ch < ' ' || (ch >= 0x7f && ch <= 0xff)) {
  568. res.AppendFormat("\\x{0:x2}", ch);
  569. } else {
  570. res.Append((char)ch);
  571. }
  572. break;
  573. }
  574. }
  575. res.Append("'");
  576. return res.ToString();
  577. }
  578. internal static List<byte>/*!*/ ZeroFill(this IList<byte>/*!*/ bytes, int width, int spaces) {
  579. List<byte> ret = new List<byte>(width);
  580. if (bytes.Count > 0 && bytes[0].IsSign()) {
  581. ret.Add(bytes[0]);
  582. for (int i = 0; i < spaces; i++) {
  583. ret.Add((byte)'0');
  584. }
  585. for (int i = 1; i < bytes.Count; i++) {
  586. ret.Add(bytes[i]);
  587. }
  588. } else {
  589. for (int i = 0; i < spaces; i++) {
  590. ret.Add((byte)'0');
  591. }
  592. ret.AddRange(bytes);
  593. }
  594. return ret;
  595. }
  596. internal static List<byte>/*!*/ ToLower(this IList<byte>/*!*/ bytes) {
  597. List<byte> res = new List<byte>();
  598. for (int i = 0; i < bytes.Count; i++) {
  599. res.Add(bytes[i].ToLower());
  600. }
  601. return res;
  602. }
  603. internal static List<byte>/*!*/ ToUpper(this IList<byte>/*!*/ bytes) {
  604. List<byte> res = new List<byte>();
  605. for (int i = 0; i < bytes.Count; i++) {
  606. res.Add(bytes[i].ToUpper());
  607. }
  608. return res;
  609. }
  610. internal static List<byte>/*!*/ Translate(this IList<byte>/*!*/ bytes, IList<byte> table, IList<byte> deletechars) {
  611. List<byte> res = new List<byte>();
  612. for (int i = 0; i < bytes.Count; i++) {
  613. if (deletechars == null || !deletechars.Contains(bytes[i])) {
  614. if (table == null) {
  615. res.Add(bytes[i]);
  616. } else {
  617. res.Add(table[bytes[i]]);
  618. }
  619. }
  620. }
  621. return res;
  622. }
  623. internal static List<byte> RightStrip(this IList<byte>/*!*/ bytes) {
  624. int i;
  625. for (i = bytes.Count - 1; i >= 0; i--) {
  626. if (!bytes[i].IsWhiteSpace()) {
  627. break;
  628. }
  629. }
  630. if (i == bytes.Count - 1) {
  631. return null;
  632. }
  633. List<byte> res = new List<byte>();
  634. for (int j = 0; j <= i; j++) {
  635. res.Add(bytes[j]);
  636. }
  637. return res;
  638. }
  639. internal static List<byte> RightStrip(this IList<byte>/*!*/ bytes, IList<byte> chars) {
  640. int i;
  641. for (i = bytes.Count - 1; i >= 0; i--) {
  642. if (!chars.Contains(bytes[i])) {
  643. break;
  644. }
  645. }
  646. if (i == bytes.Count - 1) {
  647. return null;
  648. }
  649. List<byte> res = new List<byte>();
  650. for (int j = 0; j <= i; j++) {
  651. res.Add(bytes[j]);
  652. }
  653. return res;
  654. }
  655. internal static List/*!*/ SplitLines(this IList<byte>/*!*/ bytes, bool keepends, Func<List<byte>/*!*/, object>/*!*/ ctor) {
  656. List ret = new List();
  657. int i, linestart;
  658. for (i = 0, linestart = 0; i < bytes.Count; i++) {
  659. if (bytes[i] == '\n' || bytes[i] == '\r') {
  660. // special case of "\r\n" as end of line marker
  661. if (i < bytes.Count - 1 && bytes[i] == '\r' && bytes[i + 1] == '\n') {
  662. if (keepends)
  663. ret.AddNoLock(ctor(bytes.Substring(linestart, i - linestart + 2)));
  664. else
  665. ret.AddNoLock(ctor(bytes.Substring(linestart, i - linestart)));
  666. linestart = i + 2;
  667. i++;
  668. } else { //'\r', '\n', or unicode new line as end of line marker
  669. if (keepends)
  670. ret.AddNoLock(ctor(bytes.Substring(linestart, i - linestart + 1)));
  671. else
  672. ret.AddNoLock(ctor(bytes.Substring(linestart, i - linestart)));
  673. linestart = i + 1;
  674. }
  675. }
  676. }
  677. // the last line needs to be accounted for if it is not empty
  678. if (i - linestart != 0) {
  679. ret.AddNoLock(ctor(bytes.Substring(linestart, i - linestart)));
  680. }
  681. return ret;
  682. }
  683. internal static List<byte> LeftStrip(this IList<byte>/*!*/ bytes) {
  684. int i;
  685. for (i = 0; i < bytes.Count; i++) {
  686. if (!bytes[i].IsWhiteSpace()) {
  687. break;
  688. }
  689. }
  690. if (i == 0) {
  691. return null;
  692. }
  693. List<byte> res = new List<byte>();
  694. for (; i < bytes.Count; i++) {
  695. res.Add(bytes[i]);
  696. }
  697. return res;
  698. }
  699. internal static List<byte> LeftStrip(this IList<byte>/*!*/ bytes, IList<byte> chars) {
  700. int i;
  701. for (i = 0; i < bytes.Count; i++) {
  702. if (!chars.Contains(bytes[i])) {
  703. break;
  704. }
  705. }
  706. if (i == 0) {
  707. return null;
  708. }
  709. List<byte> res = new List<byte>();
  710. for (; i < bytes.Count; i++) {
  711. res.Add(bytes[i]);
  712. }
  713. return res;
  714. }
  715. internal static List/*!*/ Split(this IList<byte>/*!*/ bytes, IList<byte> sep, int maxsplit, Func<List<byte>/*!*/, object>/*!*/ ctor) {
  716. Debug.Assert(ctor != null);
  717. if (sep == null) {
  718. if (maxsplit == 0) {
  719. // Corner case for CPython compatibility
  720. List result = PythonOps.MakeEmptyList(1);
  721. result.AddNoLock(ctor(bytes.LeftStrip() ?? bytes as List<byte> ?? new List<byte>(bytes)));
  722. return result;
  723. }
  724. return SplitInternal(bytes, (byte[])null, maxsplit, ctor);
  725. }
  726. if (sep.Count == 0) {
  727. throw PythonOps.ValueError("empty separator");
  728. } else if (sep.Count == 1) {
  729. return SplitInternal(bytes, new byte[] { sep[0] }, maxsplit, ctor);
  730. } else {
  731. return SplitInternal(bytes, sep, maxsplit, ctor);
  732. }
  733. }
  734. internal static List/*!*/ SplitInternal(IList<byte>/*!*/ bytes, byte[] seps, int maxsplit, Func<List<byte>/*!*/, object>/*!*/ ctor) {
  735. Debug.Assert(ctor != null);
  736. if (bytes.Count == 0) {
  737. return SplitEmptyString(seps != null, ctor);
  738. } else {
  739. List<byte>[] r = null;
  740. // If the optional second argument sep is absent or None, the words are separated
  741. // by arbitrary strings of whitespace characters (space, tab, newline, return, formfeed);
  742. r = bytes.Split(seps, (maxsplit < 0) ? Int32.MaxValue : maxsplit + 1,
  743. GetStringSplitOptions(seps));
  744. List ret = PythonOps.MakeEmptyList(r.Length);
  745. foreach (List<byte> s in r) {
  746. ret.AddNoLock(ctor(s));
  747. }
  748. return ret;
  749. }
  750. }
  751. private static StringSplitOptions GetStringSplitOptions(IList<byte> seps) {
  752. return (seps == null) ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None;
  753. }
  754. internal static List/*!*/ SplitInternal(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ separator, int maxsplit, Func<List<byte>/*!*/, object>/*!*/ ctor) {
  755. Debug.Assert(ctor != null);
  756. if (bytes.Count == 0) {
  757. return SplitEmptyString(separator != null, ctor);
  758. }
  759. List<byte>[] r = bytes.Split(separator, (maxsplit < 0) ? Int32.MaxValue : maxsplit + 1, GetStringSplitOptions(separator));
  760. List ret = PythonOps.MakeEmptyList(r.Length);
  761. foreach (List<byte> s in r) {
  762. ret.AddNoLock(ctor(s));
  763. }
  764. return ret;
  765. }
  766. private static List/*!*/ SplitEmptyString(bool separators, Func<List<byte>/*!*/, object>/*!*/ ctor) {
  767. Debug.Assert(ctor != null);
  768. List ret = PythonOps.MakeEmptyList(1);
  769. if (separators) {
  770. ret.AddNoLock(ctor(new List<byte>(0)));
  771. }
  772. return ret;
  773. }
  774. internal static List<byte> Strip(this IList<byte>/*!*/ bytes) {
  775. int start;
  776. for (start = 0; start < bytes.Count; start++) {
  777. if (!bytes[start].IsWhiteSpace()) {
  778. break;
  779. }
  780. }
  781. int end;
  782. for (end = bytes.Count - 1; end >= 0; end--) {
  783. if (!bytes[end].IsWhiteSpace()) {
  784. break;
  785. }
  786. }
  787. if (start == 0 && end == bytes.Count - 1) {
  788. return null;
  789. }
  790. List<byte> res = new List<byte>();
  791. for (int j = start; j <= end; j++) {
  792. res.Add(bytes[j]);
  793. }
  794. return res;
  795. }
  796. internal static List<byte> Strip(this IList<byte>/*!*/ bytes, IList<byte> chars) {
  797. int start;
  798. for (start = 0; start < bytes.Count; start++) {
  799. if (!chars.Contains(bytes[start])) {
  800. break;
  801. }
  802. }
  803. int end;
  804. for (end = bytes.Count - 1; end >= 0; end--) {
  805. if (!chars.Contains(bytes[end])) {
  806. break;
  807. }
  808. }
  809. if (start == 0 && end == bytes.Count - 1) {
  810. return null;
  811. }
  812. List<byte> res = new List<byte>();
  813. for (int j = start; j <= end; j++) {
  814. res.Add(bytes[j]);
  815. }
  816. return res;
  817. }
  818. internal static List<byte> Slice(this IList<byte>/*!*/ bytes, Slice/*!*/ slice) {
  819. if (slice == null) {
  820. throw PythonOps.TypeError("indices must be slices or integers");
  821. }
  822. int start, stop, step;
  823. slice.indices(bytes.Count, out start, out stop, out step);
  824. if (step == 1) {
  825. return stop > start ? bytes.Substring(start, stop - start) : null;
  826. }
  827. List<byte> newData;
  828. if (step > 0) {
  829. if (start > stop) {
  830. return null;
  831. }
  832. int icnt = (stop - start + step - 1) / step;
  833. newData = new List<byte>(icnt);
  834. for (int i = start; i < stop; i += step) {
  835. newData.Add(bytes[i]);
  836. }
  837. } else {
  838. if (start < stop) {
  839. return null;
  840. }
  841. int icnt = (stop - start + step + 1) / step;
  842. newData = new List<byte>(icnt);
  843. for (int i = start; i > stop; i += step) {
  844. newData.Add(bytes[i]);
  845. }
  846. }
  847. return newData;
  848. }
  849. internal static List<byte>/*!*/ SwapCase(this IList<byte>/*!*/ bytes) {
  850. List<byte> ret = new List<byte>(bytes);
  851. for (int i = 0; i < bytes.Count; i++) {
  852. byte ch = ret[i];
  853. if (ch.IsUpper()) {
  854. ret[i] = ch.ToLower();
  855. } else if (ch.IsLower()) {
  856. ret[i] = ch.ToUpper();
  857. }
  858. }
  859. return ret;
  860. }
  861. internal static bool StartsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ prefix, int start, int end) {
  862. int len = bytes.Count;
  863. if (start > len) return false;
  864. // map the negative indices to their positive counterparts
  865. else if (start < 0) {
  866. start += len;
  867. if (start < 0) start = 0;
  868. }
  869. if (end >= len) end = len;
  870. else if (end < 0) {
  871. end += len;
  872. if (end < 0) return false;
  873. }
  874. if (end < start) return false;
  875. foreach (object obj in prefix) {
  876. if (bytes.Substring(start, end - start).StartsWith(ByteOps.CoerceBytes(obj))) {
  877. return true;
  878. }
  879. }
  880. return false;
  881. }
  882. internal static bool StartsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ prefix, int start) {
  883. int len = bytes.Count;
  884. if (start > len) return false;
  885. if (start < 0) {
  886. start += len;
  887. if (start < 0) {
  888. start = 0;
  889. }
  890. }
  891. foreach (object obj in prefix) {
  892. if (bytes.Substring(start).StartsWith(ByteOps.CoerceBytes(obj))) {
  893. return true;
  894. }
  895. }
  896. return false;
  897. }
  898. internal static bool StartsWith(this IList<byte>/*!*/ bytes, PythonTuple/*!*/ prefix) {
  899. foreach (object obj in prefix) {
  900. if (bytes.StartsWith(ByteOps.CoerceBytes(obj))) {
  901. return true;
  902. }
  903. }
  904. return false;
  905. }
  906. internal static bool IsWhiteSpace(this IList<byte>/*!*/ bytes) {
  907. if (bytes.Count == 0) {
  908. return false;
  909. }
  910. foreach (byte b in bytes) {
  911. if (!b.IsWhiteSpace()) {
  912. return false;
  913. }
  914. }
  915. return true;
  916. }
  917. internal static bool IsLower(this IList<byte>/*!*/ bytes) {
  918. bool foundLower = false;
  919. foreach (byte b in bytes) {
  920. foundLower = foundLower || b.IsLower();
  921. if (b.IsUpper()) {
  922. return false;
  923. }
  924. }
  925. return foundLower;
  926. }
  927. internal static bool IsDigit(this IList<byte>/*!*/ bytes) {
  928. if (bytes.Count == 0) {
  929. return false;
  930. }
  931. foreach (byte b in bytes) {
  932. if (!b.IsDigit()) {
  933. return false;
  934. }
  935. }
  936. return true;
  937. }
  938. internal static bool IsLetter(this IList<byte>/*!*/ bytes) {
  939. if (bytes.Count == 0) {
  940. return false;
  941. }
  942. foreach (byte b in bytes) {
  943. if (!b.IsLetter()) {
  944. return false;
  945. }
  946. }
  947. return true;
  948. }
  949. internal static bool IsAlphaNumeric(this IList<byte>/*!*/ bytes) {
  950. if (bytes.Count == 0) {
  951. return false;
  952. }
  953. foreach (byte b in bytes) {
  954. if (!b.IsDigit() && !b.IsLetter()) {
  955. return false;
  956. }
  957. }
  958. return true;
  959. }
  960. internal static int Find(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sub) {
  961. if (sub == null) {
  962. throw PythonOps.TypeError("expected byte or byte array, got NoneType");
  963. }
  964. return bytes.IndexOf(sub, 0);
  965. }
  966. internal static int Find(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sub, int? start) {
  967. if (sub == null) {
  968. throw PythonOps.TypeError("expected byte or byte array, got NoneType");
  969. } else if (start > bytes.Count) {
  970. return -1;
  971. }
  972. int iStart;
  973. if (start != null) {
  974. iStart = PythonOps.FixSliceIndex(start.Value, bytes.Count);
  975. } else {
  976. iStart = 0;
  977. }
  978. return bytes.IndexOf(sub, iStart);
  979. }
  980. internal static int Find(this IList<byte>/*!*/ bytes, IList<byte>/*!*/ sub, int? start, int? end) {
  981. if (sub == null) {
  982. throw PythonOps.TypeError("expected byte or byte array, got NoneType");
  983. } else if (start > bytes.Count) {
  984. return -1;
  985. }
  986. int iStart, iEnd;
  987. iStart = FixStart(bytes, start);
  988. iEnd = FixEnd(bytes, end);
  989. if (iEnd < iStart) {
  990. return -1;
  991. }
  992. return bytes.IndexOf(sub, iStart, iEnd - iStart);
  993. }
  994. private static int FixEnd(IList<byte> bytes, int? end) {
  995. int iEnd;
  996. if (end != null) {
  997. iEnd = PythonOps.FixSliceIndex(end.Value, bytes.Count);
  998. } else {
  999. iEnd = bytes.Count;
  1000. }
  1001. return iEnd;
  1002. }
  1003. private static int FixStart(IList<byte> bytes, int? start) {
  1004. int iStart;
  1005. if (start != null) {
  1006. iStart = PythonOps.FixSliceIndex(start.Value, bytes.Count);
  1007. } else {
  1008. iStart = 0;
  1009. }
  1010. return iStart;
  1011. }
  1012. internal static byte ToByte(this string/*!*/ self, string name, int pos) {
  1013. Debug.Assert(self != null);
  1014. if (self.Length != 1 || self[0] >= 256) {
  1015. throw PythonOps.TypeError(name + "() argument " + pos + " must be char < 256, not string");
  1016. }
  1017. return (byte)self[0];
  1018. }
  1019. internal static byte ToByte(this IList<byte>/*!*/ self, string/*!*/ name, int pos) {
  1020. Debug.Assert(name != null);
  1021. if (self == null) {
  1022. throw PythonOps.TypeError(name + "() argument " + pos + " must be char < 256, not None");
  1023. } else if (self.Count != 1) {
  1024. throw PythonOps.TypeError(name + "() argument " + pos + " must be char < 256, not bytearray or bytes");
  1025. }
  1026. return self[0];
  1027. }
  1028. internal static List<byte>/*!*/ FromHex(string/*!*/ @string) {
  1029. if(@string == null) {
  1030. throw PythonOps.TypeError("expected str, got NoneType");
  1031. }
  1032. List<byte> res = new List<byte>();
  1033. for (int i = 0; i < @string.Length; i++) {
  1034. char c = @string[i];
  1035. int iVal = 0;
  1036. if (Char.IsDigit(c)) {
  1037. iVal = (c - '0') * 16;
  1038. } else if (c >= 'A' && c <= 'F') {
  1039. iVal = (c - 'A' + 10) * 16;
  1040. } else if (c >= 'a' && c <= 'f') {
  1041. iVal = (c - 'a' + 10) * 16;
  1042. } else if (c == ' ') {
  1043. continue;
  1044. } else {
  1045. throw PythonOps.ValueError("non-hexadecimal number found in fromhex() arg at position {0}", i);
  1046. }
  1047. i++;
  1048. if (i == @string.Length) {
  1049. throw PythonOps.ValueError("non-hexadecimal number found in fromhex() arg at position {0}", i - 1);
  1050. }
  1051. c = @string[i];
  1052. if (Char.IsDigit(c)) {
  1053. iVal += c - '0';
  1054. } else if (c >= 'A' && c <= 'F') {
  1055. iVal += c - 'A' + 10;
  1056. } else if (c >= 'a' && c <= 'f') {
  1057. iVal += c - 'a' + 10;
  1058. } else {
  1059. throw PythonOps.ValueError("non-hexadecimal number found in fromhex() arg at position {0}", i);
  1060. }
  1061. res.Add((byte)iVal);
  1062. }
  1063. return res;
  1064. }
  1065. #region Conversion and Enumeration
  1066. [PythonType("bytes_iterator")]
  1067. private class PythonBytesEnumerator<T> : IEnumerable, IEnumerator<T> {
  1068. private readonly IList<byte>/*!*/ _bytes;
  1069. private readonly Func<byte, T>/*!*/ _conversion;
  1070. private int _index;
  1071. public PythonBytesEnumerator(IList<byte> bytes, Func<byte, T> conversion) {
  1072. Assert.NotNull(bytes);
  1073. Assert.NotNull(conversion);
  1074. _bytes = bytes;
  1075. _conversion = conversion;
  1076. _index = -1;
  1077. }
  1078. #region IEnumerator<T> Members
  1079. public T Current {
  1080. get {
  1081. if (_index < 0) {
  1082. throw PythonOps.SystemError("Enumeration has not started. Call MoveNext.");
  1083. } else if (_index >= _bytes.Count) {
  1084. throw PythonOps.SystemError("Enumeration already finished.");
  1085. }
  1086. return _conversion(_bytes[_index]);
  1087. }
  1088. }
  1089. #endregion
  1090. #region IDisposable Members
  1091. public void Dispose() { }
  1092. #endregion
  1093. #region IEnumerator Members
  1094. object IEnumerator.Current {
  1095. get {
  1096. return ((IEnumerator<T>)this).Current;
  1097. }
  1098. }
  1099. public bool MoveNext() {
  1100. if (_index >= _bytes.Count) {
  1101. return false;
  1102. }
  1103. _index++;
  1104. return _index != _bytes.Count;
  1105. }
  1106. public void Reset() {
  1107. _index = -1;
  1108. }
  1109. #endregion
  1110. #region IEnumerable Members
  1111. public IEnumerator GetEnumerator() {
  1112. return this;
  1113. }
  1114. #endregion
  1115. }
  1116. internal static IEnumerable BytesEnumerable(IList<byte> bytes) {
  1117. return new PythonBytesEnumerator<Bytes>(bytes, b => Bytes.Make(new byte[] { b }));
  1118. }
  1119. internal static IEnumerable BytesIntEnumerable(IList<byte> bytes) {
  1120. return new PythonBytesEnumerator<int>(bytes, b => (int)b);
  1121. }
  1122. internal static IEnumerator<Bytes> BytesEnumerator(IList<byte> bytes) {
  1123. return new PythonBytesEnumerator<Bytes>(bytes, b => Bytes.Make(new byte[] { b }));
  1124. }
  1125. internal static IEnumerator<int> BytesIntEnumerator(IList<byte> bytes) {
  1126. return new PythonBytesEnumerator<int>(bytes, b => (int)b);
  1127. }
  1128. #endregion
  1129. }
  1130. }