|
1040 | 1040 | * Maximum number of bytes required to store a 32bit base 128 variable-length integer.
|
1041 | 1041 | * @type {number}
|
1042 | 1042 | * @const
|
| 1043 | + * @expose |
1043 | 1044 | */
|
1044 | 1045 | ByteBuffer.MAX_VARINT32_BYTES = 5;
|
1045 | 1046 |
|
|
1102 | 1103 | ByteBuffer.prototype.readVarint32 = function(offset) {
|
1103 | 1104 | var advance = typeof offset == 'undefined';
|
1104 | 1105 | offset = typeof offset != 'undefined' ? offset : this.offset;
|
1105 |
| - // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc |
| 1106 | + // ref: src/google/protobuf/io/coded_stream.cc |
1106 | 1107 |
|
1107 | 1108 | var src = new Uint8Array(this.array),
|
1108 | 1109 | count = 0,
|
|
1154 | 1155 | }
|
1155 | 1156 | return ByteBuffer.zigZagDecode32(dec);
|
1156 | 1157 | };
|
| 1158 | + |
| 1159 | + /** |
| 1160 | + * Maximum number of bytes required to store a 64bit base 128 variable-length integer. |
| 1161 | + * @type {number} |
| 1162 | + * @const |
| 1163 | + * @expose |
| 1164 | + */ |
| 1165 | + ByteBuffer.MAX_VARINT64_BYTES = 10; |
| 1166 | + |
| 1167 | + /** |
| 1168 | + * @type {number} |
| 1169 | + * @const |
| 1170 | + * @private |
| 1171 | + */ |
| 1172 | + var TWO_PWR_7_DBL = 1 << 7; |
| 1173 | + |
| 1174 | + /** |
| 1175 | + * @type {number} |
| 1176 | + * @const |
| 1177 | + * @private |
| 1178 | + */ |
| 1179 | + var TWO_PWR_14_DBL = TWO_PWR_7_DBL * TWO_PWR_7_DBL; |
| 1180 | + |
| 1181 | + /** |
| 1182 | + * @type {number} |
| 1183 | + * @const |
| 1184 | + * @private |
| 1185 | + */ |
| 1186 | + var TWO_PWR_21_DBL = TWO_PWR_7_DBL * TWO_PWR_14_DBL; |
| 1187 | + |
| 1188 | + /** |
| 1189 | + * @type {number} |
| 1190 | + * @const |
| 1191 | + * @private |
| 1192 | + */ |
| 1193 | + var TWO_PWR_28_DBL = TWO_PWR_14_DBL * TWO_PWR_14_DBL; |
| 1194 | + |
| 1195 | + /** |
| 1196 | + * Writes a 64bit base 128 variable-length integer as used in protobuf. |
| 1197 | + * @param {number|Long} value Value to write |
| 1198 | + * @param {number=} offset Offset to write to. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1199 | + * @return {ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. |
| 1200 | + * @throws {Error} If long support is not available |
| 1201 | + * @expose |
| 1202 | + */ |
| 1203 | + ByteBuffer.prototype.writeVarint64 = function(value, offset) { |
| 1204 | + if (!Long) { |
| 1205 | + throw(new Error("Long support is not available: See https://github.com/dcodeIO/ByteBuffer.js#on-long-int64-support for details")) |
| 1206 | + } |
| 1207 | + var advance = typeof offset == 'undefined'; |
| 1208 | + offset = typeof offset != 'undefined' ? offset : this.offset; |
| 1209 | + if (!(typeof value == 'object' && value instanceof Long)) value = Long.fromNumber(value, false); |
| 1210 | + |
| 1211 | + var part0 = value.toInt() >>> 0, |
| 1212 | + part1 = value.shiftRightUnsigned(28).toInt() >>> 0, |
| 1213 | + part2 = value.shiftRightUnsigned(56).toInt() >>> 0, |
| 1214 | + size = ByteBuffer.calculateVarint64(value), |
| 1215 | + dst = new Uint8Array(this.array); |
| 1216 | + |
| 1217 | + this.ensureCapacity(offset+size); |
| 1218 | + switch (size) { |
| 1219 | + case 10: dst[offset+9] = ((part2 >>> 7) | 0x80); |
| 1220 | + case 9 : dst[offset+8] = ((part2 ) | 0x80); |
| 1221 | + case 8 : dst[offset+7] = ((part1 >>> 21) | 0x80); |
| 1222 | + case 7 : dst[offset+6] = ((part1 >>> 14) | 0x80); |
| 1223 | + case 6 : dst[offset+5] = ((part1 >>> 7) | 0x80); |
| 1224 | + case 5 : dst[offset+4] = ((part1 ) | 0x80); |
| 1225 | + case 4 : dst[offset+3] = ((part0 >>> 21) | 0x80); |
| 1226 | + case 3 : dst[offset+2] = ((part0 >>> 14) | 0x80); |
| 1227 | + case 2 : dst[offset+1] = ((part0 >>> 7) | 0x80); |
| 1228 | + case 1 : dst[offset+0] = ((part0 ) | 0x80); |
| 1229 | + } |
| 1230 | + dst[offset+size-1] &= 0x7F; |
| 1231 | + if (advance) { |
| 1232 | + this.offset += size; |
| 1233 | + return this; |
| 1234 | + } else { |
| 1235 | + return size; |
| 1236 | + } |
| 1237 | + }; |
| 1238 | + |
| 1239 | + /** |
| 1240 | + * Reads a 32bit base 128 variable-length integer as used in protobuf. |
| 1241 | + * @param {number=} offset Offset to read from. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1242 | + * @return {Long|{value: Long, length: number}} The value read if offset is omitted, else the value read and the actual number of bytes read. |
| 1243 | + * @throws {Error} If it's not a valid varint or long support is not available |
| 1244 | + * @expose |
| 1245 | + */ |
| 1246 | + ByteBuffer.prototype.readVarint64 = function(offset) { |
| 1247 | + if (!Long) { |
| 1248 | + throw(new Error("Long support is not available: See https://github.com/dcodeIO/ByteBuffer.js#on-long-int64-support for details")) |
| 1249 | + } |
| 1250 | + var advance = typeof offset == 'undefined'; |
| 1251 | + offset = typeof offset != 'undefined' ? offset : this.offset; |
| 1252 | + var start = offset; |
| 1253 | + // ref: src/google/protobuf/io/coded_stream.cc |
| 1254 | + |
| 1255 | + var src = new Uint8Array(this.array); |
| 1256 | + var part0, part1 = 0, part2 = 0, b; |
| 1257 | + b = src[offset++]; part0 = (b & 0x7F) ; if (b & 0x80) { |
| 1258 | + b = src[offset++]; part0 |= (b & 0x7F) << 7; if (b & 0x80) { |
| 1259 | + b = src[offset++]; part0 |= (b & 0x7F) << 14; if (b & 0x80) { |
| 1260 | + b = src[offset++]; part0 |= (b & 0x7F) << 21; if (b & 0x80) { |
| 1261 | + b = src[offset++]; part1 = (b & 0x7F) ; if (b & 0x80) { |
| 1262 | + b = src[offset++]; part1 |= (b & 0x7F) << 7; if (b & 0x80) { |
| 1263 | + b = src[offset++]; part1 |= (b & 0x7F) << 14; if (b & 0x80) { |
| 1264 | + b = src[offset++]; part1 |= (b & 0x7F) << 21; if (b & 0x80) { |
| 1265 | + b = src[offset++]; part2 = (b & 0x7F) ; if (b & 0x80) { |
| 1266 | + b = src[offset++]; part2 |= (b & 0x7F) << 7; if (b & 0x80) { |
| 1267 | + throw(new Error("Data must be corrupt: Buffer overrun")); }}}}}}}}}} |
| 1268 | + var value = Long.from28Bits(part0, part1, part2, false); |
| 1269 | + if (advance) { |
| 1270 | + this.offset = offset; |
| 1271 | + return value; |
| 1272 | + } else { |
| 1273 | + return { |
| 1274 | + "value": value, |
| 1275 | + "length": offset-start |
| 1276 | + }; |
| 1277 | + } |
| 1278 | + }; |
| 1279 | + |
| 1280 | + /** |
| 1281 | + * Writes a zigzag encoded 64bit base 128 encoded variable-length integer as used in protobuf. |
| 1282 | + * @param {number} value Value to write |
| 1283 | + * @param {number=} offset Offset to write to. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1284 | + * @return {ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. |
| 1285 | + * @expose |
| 1286 | + */ |
| 1287 | + ByteBuffer.prototype.writeZigZagVarint64 = function(value, offset) { |
| 1288 | + return this.writeVarint64(ByteBuffer.zigZagEncode64(value), offset); |
| 1289 | + }; |
| 1290 | + |
| 1291 | + /** |
| 1292 | + * Reads a zigzag encoded 64bit base 128 variable-length integer as used in protobuf. |
| 1293 | + * @param {number=} offset Offset to read from. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1294 | + * @return {number|{value: number, length: number}} The value read if offset is omitted, else the value read and the actual number of bytes read. |
| 1295 | + * @throws {Error} If it's not a valid varint |
| 1296 | + * @expose |
| 1297 | + */ |
| 1298 | + ByteBuffer.prototype.readZigZagVarint64 = function(offset) { |
| 1299 | + var dec = this.readVarint64(offset); |
| 1300 | + if (typeof dec == 'object') { |
| 1301 | + dec['value'] = ByteBuffer.zigZagDecode64(dec['value']); |
| 1302 | + return dec; |
| 1303 | + } |
| 1304 | + return ByteBuffer.zigZagDecode64(dec); |
| 1305 | + }; |
1157 | 1306 |
|
1158 | 1307 | /**
|
1159 | 1308 | * Writes a base 128 variable-length integer as used in protobuf. This is an alias of {@link ByteBuffer#writeVarint32}.
|
|
1173 | 1322 | * @expose
|
1174 | 1323 | */
|
1175 | 1324 | ByteBuffer.prototype.readVarint = ByteBuffer.prototype.readVarint32;
|
| 1325 | + |
| 1326 | + /** |
| 1327 | + * Writes a zigzag encoded base 128 encoded variable-length integer as used in protobuf. This is an alias of {@link ByteBuffer#writeZigZagVarint32}. |
| 1328 | + * @param {number} value Value to write |
| 1329 | + * @param {number=} offset Offset to write to. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1330 | + * @return {ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. |
| 1331 | + * @expose |
| 1332 | + */ |
| 1333 | + ByteBuffer.prototype.writeZigZagVarint = ByteBuffer.prototype.writeZigZagVarint32; |
| 1334 | + |
| 1335 | + /** |
| 1336 | + * Reads a zigzag encoded base 128 variable-length integer as used in protobuf. This is an alias of {@link ByteBuffer#readZigZagVarint32}. |
| 1337 | + * @param {number=} offset Offset to read from. Defaults to {@link ByteBuffer#offset} which will be modified only if omitted. |
| 1338 | + * @return {number|{value: number, length: number}} The value read if offset is omitted, else the value read and the actual number of bytes read. |
| 1339 | + * @throws {Error} If it's not a valid varint |
| 1340 | + * @expose |
| 1341 | + */ |
| 1342 | + ByteBuffer.prototype.readZigZagVarint = ByteBuffer.prototype.readZigZagVarint32; |
1176 | 1343 |
|
1177 | 1344 | /**
|
1178 | 1345 | * Calculates the actual number of bytes required to encode a 32bit base 128 variable-length integer.
|
1179 | 1346 | * @param {number} value Value to encode
|
1180 |
| - * @return {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT32_BYTES} (35bit), no overflow errors. |
| 1347 | + * @return {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT32_BYTES} (35bit). No overflow error. |
1181 | 1348 | * @expose
|
1182 | 1349 | */
|
1183 | 1350 | ByteBuffer.calculateVarint32 = function(value) {
|
1184 |
| - // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc |
1185 |
| - ByteBuffer.UINT32[0] = value; |
1186 |
| - if (ByteBuffer.UINT32[0] < 0x80) { |
| 1351 | + // ref: src/google/protobuf/io/coded_stream.cc |
| 1352 | + value = value >>> 0; |
| 1353 | + if (value < TWO_PWR_7_DBL) { |
1187 | 1354 | return 1;
|
1188 |
| - } else if (ByteBuffer.UINT32[0] < 0x4000) { |
| 1355 | + } else if (value < TWO_PWR_14_DBL) { |
1189 | 1356 | return 2;
|
1190 |
| - } else if (ByteBuffer.UINT32[0] < 0x200000) { |
| 1357 | + } else if (value < TWO_PWR_21_DBL) { |
1191 | 1358 | return 3;
|
1192 |
| - } else if (ByteBuffer.UINT32[0] < 0x10000000) { |
| 1359 | + } else if (value < TWO_PWR_28_DBL) { |
1193 | 1360 | return 4;
|
1194 | 1361 | } else {
|
1195 | 1362 | return 5;
|
1196 |
| - } // As this is casted, we can't throw an overflow error. |
| 1363 | + } |
| 1364 | + }; |
| 1365 | + |
| 1366 | + /** |
| 1367 | + * Calculates the actual number of bytes required to encode a 64bit base 128 variable-length integer. |
| 1368 | + * @param {number|Long} value Value to encode |
| 1369 | + * @return {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT64_BYTES}. No overflow error. |
| 1370 | + * @throws {Error} If long support is not available |
| 1371 | + * @expose |
| 1372 | + */ |
| 1373 | + ByteBuffer.calculateVarint64 = function(value) { |
| 1374 | + if (!Long) { |
| 1375 | + throw(new Error("Long support is not available: See https://github.com/dcodeIO/ByteBuffer.js#on-long-int64-support for details")) |
| 1376 | + } |
| 1377 | + // ref: src/google/protobuf/io/coded_stream.cc |
| 1378 | + if (!(typeof value == 'object' && value instanceof Long)) value = Long.fromNumber(value, false); |
| 1379 | + |
| 1380 | + var part0 = value.toInt() >>> 0, |
| 1381 | + part1 = value.shiftRightUnsigned(28).toInt() >>> 0, |
| 1382 | + part2 = value.shiftRightUnsigned(56).toInt() >>> 0; |
| 1383 | + |
| 1384 | + if (part2 == 0) { |
| 1385 | + if (part1 == 0) { |
| 1386 | + if (part0 < TWO_PWR_14_DBL) { |
| 1387 | + return part0 < TWO_PWR_7_DBL ? 1 : 2; |
| 1388 | + } else { |
| 1389 | + return part0 < TWO_PWR_21_DBL ? 3 : 4; |
| 1390 | + } |
| 1391 | + } else { |
| 1392 | + if (part1 < TWO_PWR_14_DBL) { |
| 1393 | + return part1 < TWO_PWR_7_DBL ? 5 : 6; |
| 1394 | + } else { |
| 1395 | + return part1 < TWO_PWR_21_DBL ? 7 : 8; |
| 1396 | + } |
| 1397 | + } |
| 1398 | + } else { |
| 1399 | + return part2 < TWO_PWR_7_DBL ? 9 : 10; |
| 1400 | + } |
1197 | 1401 | };
|
1198 | 1402 |
|
1199 | 1403 | /**
|
1200 |
| - * Encodes a signed integer so that it can be effectively used with varint encoding. |
1201 |
| - * @param {number} n Signed integer |
1202 |
| - * @return {number} Unsigned, zigzag encoded integer |
| 1404 | + * Encodes a signed 32bit integer so that it can be effectively used with varint encoding. |
| 1405 | + * @param {number} n Signed 32bit integer |
| 1406 | + * @return {number} Unsigned zigzag encoded 32bit integer |
1203 | 1407 | * @expose
|
1204 | 1408 | */
|
1205 | 1409 | ByteBuffer.zigZagEncode32 = function(n) {
|
1206 |
| - ByteBuffer.INT32[0]=n; |
1207 |
| - return ((n=ByteBuffer.INT32[0])>=0) ? n*2 : -n*2-1; // If we'd have real 32bit arithmetic: (n << 1) ^ (n >> 31); |
| 1410 | + // ref: src/google/protobuf/wire_format_lite.h |
| 1411 | + return (((n |= 0) << 1) ^ (n >> 31)) >>> 0; |
1208 | 1412 | };
|
1209 | 1413 |
|
1210 | 1414 | /**
|
1211 |
| - * Decodes a zigzag encoded signed integer. |
1212 |
| - * @param {number} n Unsigned zigzag encoded integer |
1213 |
| - * @return {number} Signed integer |
| 1415 | + * Decodes a zigzag encoded signed 32bit integer. |
| 1416 | + * @param {number} n Unsigned zigzag encoded 32bit integer |
| 1417 | + * @return {number} Signed 32bit integer |
1214 | 1418 | * @expose
|
1215 | 1419 | */
|
1216 | 1420 | ByteBuffer.zigZagDecode32 = function(n) {
|
1217 |
| - ByteBuffer.UINT32[0]=n; |
1218 |
| - return (((n=ByteBuffer.UINT32[0])&1)==0) ? n/2 : -(n+1)/2; // If we'd have real 32bit arithmetic: (n >> 1) ^ -(n & 1); |
| 1421 | + // ref: src/google/protobuf/wire_format_lite.h |
| 1422 | + return ((n >>> 1) ^ -(n & 1)) | 0; |
| 1423 | + }; |
| 1424 | + |
| 1425 | + /** |
| 1426 | + * Encodes a signed 64bit integer so that it can be effectively used with varint encoding. |
| 1427 | + * @param {number|Long} n Signed long |
| 1428 | + * @return {Long} Unsigned zigzag encoded long |
| 1429 | + * @expose |
| 1430 | + */ |
| 1431 | + ByteBuffer.zigZagEncode64 = function(n) { |
| 1432 | + // ref: src/google/protobuf/wire_format_lite.h |
| 1433 | + if (typeof n == 'object' && n instanceof Long) { |
| 1434 | + if (n.unsigned) n = n.toSigned(); |
| 1435 | + } else { |
| 1436 | + n = Long.fromNumber(n, false); |
| 1437 | + } |
| 1438 | + return n.shiftLeft(1).xor(n.shiftRight(63)).toUnsigned(); |
| 1439 | + }; |
| 1440 | + |
| 1441 | + /** |
| 1442 | + * Decodes a zigzag encoded signed 64bit integer. |
| 1443 | + * @param {Long} n Unsigned zigzag encoded long |
| 1444 | + * @return {Long} Signed long |
| 1445 | + * @expose |
| 1446 | + */ |
| 1447 | + ByteBuffer.zigZagDecode64 = function(n) { |
| 1448 | + // ref: src/google/protobuf/wire_format_lite.h |
| 1449 | + if (typeof n == 'object' && n instanceof Long) { |
| 1450 | + if (!n.unsigned) n = n.toUnsigned(); |
| 1451 | + } else { |
| 1452 | + n = Long.fromNumber(n, true); |
| 1453 | + } |
| 1454 | + return n.shiftRightUnsigned(1).xor(n.and(Long.ONE).toSigned().negate()).toSigned(); |
1219 | 1455 | };
|
1220 | 1456 |
|
1221 | 1457 | /**
|
|
0 commit comments