public PackIndexV2(Stream fd) { var fanoutRaw = new byte[4 * FANOUT]; IO.ReadFully(fd, fanoutRaw, 0, fanoutRaw.Length); _fanoutTable = new long[FANOUT]; for (int k = 0; k < FANOUT; k++) { _fanoutTable[k] = NB.DecodeUInt32(fanoutRaw, k * 4); } ObjectCount = _fanoutTable[FANOUT - 1]; _names = new int[FANOUT][]; _offset32 = new byte[FANOUT][]; _crc32 = new byte[FANOUT][]; // object name table. The size we can permit per fan-out bucket // is limited to Java's 2 GB per byte array limitation. That is // no more than 107,374,182 objects per fan-out. // for (int k = 0; k < FANOUT; k++) { long bucketCnt; if (k == 0) { bucketCnt = _fanoutTable[k]; } else { bucketCnt = _fanoutTable[k] - _fanoutTable[k - 1]; } if (bucketCnt == 0) { _names[k] = NoInts; _offset32[k] = NoBytes; _crc32[k] = NoBytes; continue; } long nameLen = bucketCnt * Constants.OBJECT_ID_LENGTH; if (nameLen > int.MaxValue) { throw new IOException("Index file is too large"); } var intNameLen = (int)nameLen; var raw = new byte[intNameLen]; var bin = new int[intNameLen >> 2]; IO.ReadFully(fd, raw, 0, raw.Length); for (int i = 0; i < bin.Length; i++) { bin[i] = NB.DecodeInt32(raw, i << 2); } _names[k] = bin; _offset32[k] = new byte[(int)(bucketCnt * 4)]; _crc32[k] = new byte[(int)(bucketCnt * 4)]; } // CRC32 table. for (int k = 0; k < FANOUT; k++) { IO.ReadFully(fd, _crc32[k], 0, _crc32[k].Length); } // 32 bit offset table. Any entries with the most significant bit // set require a 64 bit offset entry in another table. // int o64cnt = 0; for (int k = 0; k < FANOUT; k++) { byte[] ofs = _offset32[k]; IO.ReadFully(fd, ofs, 0, ofs.Length); for (int p = 0; p < ofs.Length; p += 4) { if (NB.ConvertUnsignedByteToSigned(ofs[p]) < 0) { o64cnt++; } } } // 64 bit offset table. Most objects should not require an entry. // if (o64cnt > 0) { _offset64 = new byte[o64cnt * 8]; IO.ReadFully(fd, _offset64, 0, _offset64.Length); } else { _offset64 = NoBytes; } PackChecksum = new byte[20]; IO.ReadFully(fd, PackChecksum, 0, PackChecksum.Length); }