/// <summary> /// Decompresses the given bitinput using the GPX compression format. Only use this method /// if you are sure the binary data is compressed using the GPX format. Otherwise unexpected /// behavior can occure. /// </summary> /// <param name="src">the bitInput to read the data from</param> /// <param name="skipHeader">true if the header should NOT be included in the result byteset, otherwise false</param> /// <returns>the decompressed byte data. if skipHeader is set to false the BCFS header is included.</returns> public byte[] Decompress(BitReader src, bool skipHeader = false) { var uncompressed = ByteBuffer.Empty(); byte[] buffer; var expectedLength = GetInteger(src.ReadBytes(4), 0); try { // as long we reach our expected length we try to decompress, a EOF might occure. while (uncompressed.Length < expectedLength) { // compression flag var flag = src.ReadBits(1); if (flag == 1) // compressed content { // get offset and size of the content we need to read. // compressed does mean we already have read the data and need // to copy it from our uncompressed buffer to the end var wordSize = src.ReadBits(4); var offset = src.ReadBitsReversed(wordSize); var size = src.ReadBitsReversed(wordSize); // the offset is relative to the end var sourcePosition = uncompressed.Length - offset; var toRead = Math.Min(offset, size); // get the subbuffer storing the data and add it again to the end buffer = uncompressed.GetBuffer(); uncompressed.Write(buffer, (int) sourcePosition, toRead); } else // raw content { // on raw content we need to read the data from the source buffer var size = src.ReadBitsReversed(2); for (int i = 0; i < size; i++) { uncompressed.WriteByte((byte) src.ReadByte()); } } } } catch (EndOfReaderException) { } buffer = uncompressed.GetBuffer(); var resultOffset = skipHeader ? 4 : 0; var resultSize = uncompressed.Length - resultOffset; var result = new byte[(int)resultSize]; Std.BlockCopy(buffer, resultOffset, result, 0, (int)resultSize); return result; }
/// <summary> /// Load a complete FileSystem to the memory. /// </summary> /// <param name="s">the binary source to read from.</param> /// <returns></returns> public void Load(IReadable s) { var src = new BitReader(s); ReadBlock(src); }
/// <summary> /// Reads the 4 byte header as a string. /// </summary> /// <param name="src">the BitInput to read from</param> /// <returns>a string with 4 characters representing the header.</returns> public string ReadHeader(BitReader src) { return GetString(src.ReadBytes(4), 0, 4); }
/// <summary> /// Reads a block from the given data source. /// </summary> /// <param name="data">the data source</param> /// <returns></returns> private void ReadBlock(BitReader data) { var header = ReadHeader(data); if (header == HeaderBcFz) // compressed file? { // decompress the data and use this // we will skip the header ReadUncompressedBlock(Decompress(data, true)); } else if (header == HeaderBcFs) // uncompressed file? { ReadUncompressedBlock(data.ReadAll()); } else { throw new UnsupportedFormatException(); } }