Guest User

Untitled

a guest
Feb 17th, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.30 KB | None | 0 0
  1. import { Int64 } from './compat/long';
  2.  
  3. export type Double = number;
  4. export type Float = number;
  5. export type Int32 = number;
  6. export type Int64 = Long;
  7. export type Uint32 = number;
  8. export type Uint64 = Long;
  9. export type Sint32 = number;
  10. export type Sint64 = Long;
  11. export type Fixed32 = number;
  12. export type Fixed64 = Long;
  13. export type Sfixed32 = number;
  14. export type Sfixed64 = Long;
  15. export type Bytes = Uint8Array;
  16. export type Byte = number;
  17.  
  18. export interface Long {
  19. readonly low: Uint32;
  20. readonly high: Uint32;
  21. toString(): string;
  22. unsafeToNumber(): number;
  23. }
  24.  
  25. export interface ByteInputStream {
  26. hasNext(): boolean;
  27. take(n: number): () => boolean;
  28. read(): Byte;
  29. skip(n: number): void;
  30. }
  31.  
  32. export interface ByteOutputStream {
  33. write(byte: Byte): void;
  34. toBytes(): Uint8Array;
  35. }
  36.  
  37. export class Uint8ArrayInputStream implements ByteInputStream {
  38. private offset = 0;
  39. private readonly byteLength: number;
  40.  
  41. constructor(private readonly bytes: Uint8Array) {
  42. this.byteLength = bytes.byteLength;
  43. }
  44.  
  45. hasNext(): boolean {
  46. return this.offset < this.byteLength;
  47. }
  48.  
  49. take(n: number): () => boolean {
  50. const end = this.offset + n;
  51. return () => this.offset < end;
  52. }
  53.  
  54. read(): Byte {
  55. return this.bytes[this.offset++];
  56. }
  57.  
  58. skip(n: number): void {
  59. this.offset += n;
  60. }
  61. }
  62.  
  63. export class Uint8ArrayOutputStream implements ByteOutputStream {
  64. private offset = 0;
  65. private bytes = new Uint8Array(16);
  66.  
  67. write(byte: Byte) {
  68. this.bytes[this.offset++] = byte;
  69. }
  70.  
  71. toBytes(): Uint8Array {
  72. return this.bytes.slice(0, this.offset);
  73. }
  74. }
  75.  
  76. export function readUint32(stream: ByteInputStream): number {
  77. let byte = stream.read();
  78. let value = byte & 0x7F;
  79. if (byte < 0x80) {
  80. return value;
  81. }
  82.  
  83. byte = stream.read();
  84. value |= (byte & 0x7F) << 7;
  85. if (byte < 0x80) {
  86. return value;
  87. }
  88.  
  89. byte = stream.read();
  90. value |= (byte & 0x7F) << 14;
  91. if (byte < 0x80) {
  92. return value;
  93. }
  94.  
  95. byte = stream.read();
  96. value |= (byte & 0x7F) << 21;
  97. if (byte < 0x80) {
  98. return value;
  99. }
  100.  
  101. byte = stream.read();
  102. value |= (byte & 0x7F) << 28;
  103. if (byte < 0x80) {
  104. return value >>> 0;
  105. }
  106.  
  107. // If we get here, it's a negative integer
  108. // Since we already read 5 bytes, we will skip over the remaining 5
  109. stream.skip(5);
  110.  
  111. return value;
  112. }
  113.  
  114. export function readSint32(stream: ByteInputStream): number {
  115. const uint32 = readUint32(stream);
  116. return (uint32 >>> 1) ^ - (uint32 & 1);
  117. }
  118.  
  119. export function readInt64(stream: ByteInputStream): string {
  120. let temp;
  121. let low = 0;
  122. let high = 0;
  123.  
  124. // Read the first four bytes of the varint, stopping at the terminator if we
  125. // see it.
  126. for (let i = 0; i < 4; i++) {
  127. temp = stream.read();
  128. low |= (temp & 0x7F) << (i * 7);
  129. if (temp < 128) {
  130. return new Int64(low >>> 0, 0).toString();
  131. }
  132. }
  133.  
  134. // Read the fifth byte, which straddles the low and high dwords.
  135. temp = stream.read();
  136. low |= (temp & 0x7F) << 28;
  137. high |= (temp & 0x7F) >> 4;
  138. if (temp < 128) {
  139. return new Int64(low >>> 0, high >>> 0).toString();
  140. }
  141.  
  142. // Read the sixth through tenth byte.
  143. for (let i = 0; i < 5; i++) {
  144. temp = stream.read();
  145. high |= (temp & 0x7F) << (i * 7 + 3);
  146. if (temp < 128) {
  147. return new Int64(low >>> 0, high >>> 0).toString();
  148. }
  149. }
  150.  
  151. return new Int64(low, high).toString();
  152. }
  153.  
  154. export function readFixed32(stream: ByteInputStream): number {
  155. const a = stream.read();
  156. const b = stream.read();
  157. const c = stream.read();
  158. const d = stream.read();
  159. return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
  160. }
  161.  
  162. export function readFloat(stream: ByteInputStream): number {
  163. const bits = readFixed32(stream);
  164. const sign = ((bits >> 31) * 2 + 1);
  165. const exp = (bits >>> 23) & 0xFF;
  166. const mantissa = bits & 0x7FFFFF;
  167.  
  168. if (exp === 0xFF) {
  169. if (mantissa) {
  170. return NaN;
  171. } else {
  172. return sign * Infinity;
  173. }
  174. }
  175.  
  176. if (exp === 0) {
  177. // Denormal.
  178. return sign * 1.401298464324817e-45 * mantissa;
  179. } else {
  180. return sign * Math.pow(2, exp - 150) *
  181. (mantissa + 8388608);
  182. }
  183. }
  184.  
  185. export function readDouble(stream: ByteInputStream): number {
  186. const low = readFixed32(stream);
  187. const high = readFixed32(stream);
  188. const sign = ((high >> 31) * 2 + 1);
  189. const exp = (high >>> 20) & 0x7FF;
  190. const mant = 4294967296 * (high & 0xFFFFF) + low;
  191.  
  192. if (exp === 0x7FF) {
  193. if (mant) {
  194. return NaN;
  195. } else {
  196. return sign * Infinity;
  197. }
  198. }
  199.  
  200. if (exp === 0) {
  201. // Denormal.
  202. return sign * 5e-324 * mant;
  203. } else {
  204. return sign * Math.pow(2, exp - 1075) * (mant + 4503599627370496);
  205. }
  206. }
  207.  
  208. export function readBoolean(stream: ByteInputStream): boolean {
  209. return !!readUint32(stream);
  210. }
  211.  
  212. export function readPackedBoolean(stream: ByteInputStream, array: boolean[]): boolean[] {
  213. const length = readUint32(stream);
  214. const next = stream.take(length);
  215. while (next()) {
  216. array.push(readBoolean(stream));
  217. }
  218. return array;
  219. }
  220.  
  221. export function readString(stream: ByteInputStream): string {
  222. const length = readUint32(stream);
  223. const codeUnits = new Array(length);
  224.  
  225. let charactersRead = 0;
  226. let cursor = 0;
  227. let result = '';
  228.  
  229. while (cursor < length) {
  230. const c = stream.read(); cursor++;
  231. if (c < 128) { // Regular 7-bit ASCII.
  232. codeUnits[charactersRead++] = c;
  233. } else if (c < 192) {
  234. // UTF-8 continuation mark. We are out of sync. This
  235. // might happen if we attempted to read a character
  236. // with more than four bytes.
  237. continue;
  238. } else if (c < 224) { // UTF-8 with two bytes.
  239. const c2 = stream.read(); cursor++;
  240. codeUnits[charactersRead++] = ((c & 31) << 6) | (c2 & 63);
  241. } else if (c < 240) { // UTF-8 with three bytes.
  242. const c2 = stream.read(); cursor++;
  243. const c3 = stream.read(); cursor++;
  244. codeUnits[charactersRead++] = ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63);
  245. } else if (c < 248) { // UTF-8 with 4 bytes.
  246. const c2 = stream.read(); cursor++;
  247. const c3 = stream.read(); cursor++;
  248. const c4 = stream.read(); cursor++;
  249. // Characters written on 4 bytes have 21 bits for a codepoint.
  250. // We can't fit that on 16bit characters, so we use surrogates.
  251. let codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
  252. // Surrogates formula from wikipedia.
  253. // 1. Subtract 0x10000 from codepoint
  254. codepoint -= 0x10000;
  255. // 2. Split this into the high 10-bit value and the low 10-bit value
  256. // 3. Add 0xD800 to the high value to form the high surrogate
  257. // 4. Add 0xDC00 to the low value to form the low surrogate:
  258. const low = (codepoint & 1023) + 0xDC00;
  259. const high = ((codepoint >> 10) & 1023) + 0xD800;
  260. codeUnits[charactersRead++] = high;
  261. codeUnits[charactersRead++] = low;
  262. }
  263. }
  264.  
  265. // TODO chunk it if length exceeds 8192
  266. result += String.fromCharCode.apply(null, codeUnits);
  267.  
  268. return result;
  269. }
  270.  
  271. export function writeUint32(value: number, stream: ByteOutputStream) {
  272. while (value > 0x7F) {
  273. stream.write((value & 0x7F) | 0x80);
  274. value = value >>> 7;
  275. }
  276. stream.write(value);
  277. }
  278.  
  279. export function writeSint32(value: number, stream: ByteOutputStream) {
  280. writeUint32(((value << 1) ^ (value >> 31)) >>> 0, stream);
  281. }
  282.  
  283. export function writeInt64(value: string, stream: ByteOutputStream) {
  284. const int64 = Int64.fromString(value);
  285. writeInt64FromBits(int64.low, int64.high, stream);
  286. }
  287.  
  288. function writeInt64FromBits(low: number, high: number, stream: ByteOutputStream) {
  289. // Break the binary representation into chunks of 7 bits, set the 8th bit
  290. // in each chunk if it's not the final chunk, and append to the result.
  291. while (high > 0 || low > 127) {
  292. stream.write((low & 0x7f) | 0x80);
  293. low = ((low >>> 7) | (high << 25)) >>> 0;
  294. high = high >>> 7;
  295. }
  296. stream.write(low);
  297. }
  298.  
  299. export function writeFloat(value: number, stream: ByteOutputStream) {
  300. const sign = (value < 0) ? 1 : 0;
  301. value = sign ? -value : value;
  302.  
  303. // Handle zeros.
  304. if (value === 0) {
  305. if ((1 / value) > 0) {
  306. // Positive zero.
  307. writeFixed32(0x00000000, stream);
  308. } else {
  309. // Negative zero.
  310. writeFixed32(0x80000000, stream);
  311. }
  312. return;
  313. }
  314.  
  315. // Handle nans.
  316. if (isNaN(value)) {
  317. writeFixed32(0x7FFFFFFF, stream);
  318. return;
  319. }
  320.  
  321. // Handle infinities.
  322. if (value > 3.4028234663852886e+38) {
  323. writeFixed32(((sign << 31) | (0x7F800000)) >>> 0, stream);
  324. return;
  325. }
  326.  
  327. // Handle denormals.
  328. if (value < 1.1754943508222875e-38) {
  329. const mantissa = Math.round(value / 1.401298464324817e-45);
  330. writeFixed32(((sign << 31) | mantissa) >>> 0, stream);
  331. } else {
  332. const exp = Math.floor(Math.log(value) / Math.LN2);
  333. const mantissa = Math.round(value * Math.pow(2, -exp) * 8388608);
  334. writeFixed32(((sign << 31) | ((exp + 127) << 23) | mantissa & 0x7FFFFF) >>> 0, stream);
  335. }
  336. }
  337.  
  338. export function writeDouble(value: number, stream: ByteOutputStream) {
  339. const sign = (value < 0) ? 1 : 0;
  340. value = sign ? -value : value;
  341.  
  342. // Handle zeros.
  343. if (value === 0) {
  344. if ((1 / value) > 0) {
  345. // Positive zero.
  346. writeFixed32(0x00000000, stream);
  347. writeFixed32(0x00000000, stream);
  348. } else {
  349. // Negative zero.
  350. writeFixed32(0x00000000, stream);
  351. writeFixed32(0x80000000, stream);
  352. }
  353. return;
  354. }
  355.  
  356. // Handle nans.
  357. if (isNaN(value)) {
  358. writeFixed32(0x7FFFFFFF, stream);
  359. writeFixed32(0xFFFFFFFF, stream);
  360. return;
  361. }
  362.  
  363. // Handle infinities.
  364. if (value > 1.7976931348623157e+308) {
  365. writeFixed32(0, stream);
  366. writeFixed32(((sign << 31) | (0x7FF00000)) >>> 0, stream);
  367. return;
  368. }
  369.  
  370. // Handle denormals.
  371. if (value < 2.2250738585072014e-308) {
  372. // Number is a denormal.
  373. const mant = value / 5e-324;
  374. const mantHigh = (mant / 8388608);
  375. writeFixed32(mant >>> 0, stream);
  376. writeFixed32(((sign << 31) | mantHigh) >>> 0, stream);
  377. } else {
  378. const exp = Math.min(Math.floor(Math.log(value) / Math.LN2), 1023);
  379. const mant = value * Math.pow(2, -exp);
  380. const mantHigh = (mant * 1048576) & 0xFFFFF;
  381. const mantLow = (mant * 4503599627370496) >>> 0;
  382. writeFixed32(mantLow, stream);
  383. writeFixed32(((sign << 31) | ((exp + 1023) << 20) | mantHigh) >>> 0, stream);
  384. }
  385. }
  386.  
  387. export function writeFixed32(value: number, stream: ByteOutputStream) {
  388. stream.write((value >>> 0) & 0xFF);
  389. stream.write((value >>> 8) & 0xFF);
  390. stream.write((value >>> 16) & 0xFF);
  391. stream.write((value >>> 24) & 0xFF);
  392. }
  393.  
  394. export function writeBoolean(value: boolean, stream: ByteOutputStream) {
  395. writeUint32(value ? 1 : 0, stream);
  396. }
Add Comment
Please, Sign In to add comment