DataRun.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. namespace DiskAccessLibrary.FileSystems.NTFS
  11. {
  12. public class DataRun
  13. {
  14. // The maximum NTFS file size is 2^64 bytes, so total number of file clusters can be represented using long
  15. // http://technet.microsoft.com/en-us/library/cc938937.aspx
  16. public long RunLength; // In clusters
  17. public long RunOffset; // In clusters, relative to previous data run start LCN
  18. public bool IsSparse;
  19. /// <returns>Run length</returns>
  20. public int Read(byte[] buffer, int offset)
  21. {
  22. int runOffsetSize = buffer[offset] >> 4;
  23. int runLengthSize = buffer[offset] & 0x0F;
  24. RunLength = ReadVarLong(ref buffer, offset + 1, runLengthSize);
  25. RunOffset = ReadVarLong(ref buffer, offset + 1 + runLengthSize, runOffsetSize);
  26. IsSparse = runOffsetSize == 0;
  27. return 1 + runLengthSize + runOffsetSize;
  28. }
  29. public byte[] GetBytes()
  30. {
  31. byte[] buffer = new byte[RecordLength];
  32. int runLengthSize = WriteVarLong(buffer, 1, RunLength);
  33. int runOffsetSize;
  34. if (IsSparse)
  35. {
  36. runOffsetSize = 0;
  37. }
  38. else
  39. {
  40. runOffsetSize = WriteVarLong(buffer, 1 + runLengthSize, RunOffset);
  41. }
  42. buffer[0] = (byte)((runLengthSize & 0x0F) | ((runOffsetSize << 4) & 0xF0));
  43. return buffer;
  44. }
  45. private static long ReadVarLong(ref byte[] buffer, int offset, int size)
  46. {
  47. ulong val = 0;
  48. bool signExtend = false;
  49. for (int i = 0; i < size; ++i)
  50. {
  51. byte b = buffer[offset + i];
  52. val = val | (((ulong)b) << (i * 8));
  53. signExtend = (b & 0x80) != 0;
  54. }
  55. if (signExtend)
  56. {
  57. for (int i = size; i < 8; ++i)
  58. {
  59. val = val | (((ulong)0xFF) << (i * 8));
  60. }
  61. }
  62. return (long)val;
  63. }
  64. private static int WriteVarLong(byte[] buffer, int offset, long val)
  65. {
  66. bool isPositive = val >= 0;
  67. int pos = 0;
  68. do
  69. {
  70. buffer[offset + pos] = (byte)(val & 0xFF);
  71. val >>= 8;
  72. pos++;
  73. }
  74. while (val != 0 && val != -1);
  75. // Avoid appearing to have a negative number that is actually positive,
  76. // record an extra empty byte if needed.
  77. if (isPositive && (buffer[offset + pos - 1] & 0x80) != 0)
  78. {
  79. buffer[offset + pos] = 0;
  80. pos++;
  81. }
  82. else if (!isPositive && (buffer[offset + pos - 1] & 0x80) != 0x80)
  83. {
  84. buffer[offset + pos] = 0xFF;
  85. pos++;
  86. }
  87. return pos;
  88. }
  89. private static int VarLongSize(long val)
  90. {
  91. bool isPositive = val >= 0;
  92. bool lastByteHighBitSet = false;
  93. int len = 0;
  94. do
  95. {
  96. lastByteHighBitSet = (val & 0x80) != 0;
  97. val >>= 8;
  98. len++;
  99. }
  100. while (val != 0 && val != -1);
  101. if ((isPositive && lastByteHighBitSet) || (!isPositive && !lastByteHighBitSet))
  102. {
  103. len++;
  104. }
  105. return len;
  106. }
  107. /// <summary>
  108. /// Length of the DataRun record inside the non-resident attribute record
  109. /// </summary>
  110. public int RecordLength
  111. {
  112. get
  113. {
  114. int runLengthSize = VarLongSize(RunLength);
  115. int runOffsetSize = VarLongSize(RunOffset);
  116. return 1 + runLengthSize + runOffsetSize;
  117. }
  118. }
  119. }
  120. }