| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using System.Globalization; | 
 
 
 
 
 | 4 | using System.IO; | 
 
 
 
 
 | 5 | using System.Text; | 
 
 
 
 
 | 6 | using Oni.Imaging; | 
 
 
 
 
 | 7 |  | 
 
 
 
 
 | 8 | namespace Oni | 
 
 
 
 
 | 9 | { | 
 
 
 
 
 | 10 | internal class BinaryWriter : System.IO.BinaryWriter | 
 
 
 
 
 | 11 | { | 
 
 
 
 
 | 12 | private static readonly byte[] padding = new byte[32]; | 
 
 
 
 
 | 13 | private static readonly Encoding encoding = Encoding.UTF8; | 
 
 
 
 
 | 14 | private readonly Stack<int> positionStack = new Stack<int>(); | 
 
 
 
 
 | 15 |  | 
 
 
 
 
 | 16 | public BinaryWriter(Stream stream) | 
 
 
 
 
 | 17 | : base(stream, encoding) | 
 
 
 
 
 | 18 | { | 
 
 
 
 
 | 19 | } | 
 
 
 
 
 | 20 |  | 
 
 
 
 
 | 21 | public void WriteInstanceId(int index) | 
 
 
 
 
 | 22 | { | 
 
 
 
 
 | 23 | Write(InstanceFileWriter.MakeInstanceId(index)); | 
 
 
 
 
 | 24 | } | 
 
 
 
 
 | 25 |  | 
 
 
 
 
 | 26 | public void Write(IEnumerable<ImporterDescriptor> descriptors) | 
 
 
 
 
 | 27 | { | 
 
 
 
 
 | 28 | foreach (var descriptor in descriptors) | 
 
 
 
 
 | 29 | Write(descriptor); | 
 
 
 
 
 | 30 | } | 
 
 
 
 
 | 31 |  | 
 
 
 
 
 | 32 | public void Write(ImporterDescriptor descriptor) | 
 
 
 
 
 | 33 | { | 
 
 
 
 
 | 34 | if (descriptor == null) | 
 
 
 
 
 | 35 | Write(0); | 
 
 
 
 
 | 36 | else | 
 
 
 
 
 | 37 | Write(InstanceFileWriter.MakeInstanceId(descriptor.Index)); | 
 
 
 
 
 | 38 | } | 
 
 
 
 
 | 39 |  | 
 
 
 
 
 | 40 | public void Write(Color c) | 
 
 
 
 
 | 41 | { | 
 
 
 
 
 | 42 | Write(c.ToBgra32()); | 
 
 
 
 
 | 43 | } | 
 
 
 
 
 | 44 |  | 
 
 
 
 
 | 45 | public void Write(Vector2 v) | 
 
 
 
 
 | 46 | { | 
 
 
 
 
 | 47 | Write(v.X); | 
 
 
 
 
 | 48 | Write(v.Y); | 
 
 
 
 
 | 49 | } | 
 
 
 
 
 | 50 |  | 
 
 
 
 
 | 51 | public void Write(Vector3 v) | 
 
 
 
 
 | 52 | { | 
 
 
 
 
 | 53 | Write(v.X); | 
 
 
 
 
 | 54 | Write(v.Y); | 
 
 
 
 
 | 55 | Write(v.Z); | 
 
 
 
 
 | 56 | } | 
 
 
 
 
 | 57 |  | 
 
 
 
 
 | 58 | public void Write(Vector4 v) | 
 
 
 
 
 | 59 | { | 
 
 
 
 
 | 60 | Write(v.X); | 
 
 
 
 
 | 61 | Write(v.Y); | 
 
 
 
 
 | 62 | Write(v.Z); | 
 
 
 
 
 | 63 | Write(v.W); | 
 
 
 
 
 | 64 | } | 
 
 
 
 
 | 65 |  | 
 
 
 
 
 | 66 | public void Write(Quaternion q) | 
 
 
 
 
 | 67 | { | 
 
 
 
 
 | 68 | Write(q.X); | 
 
 
 
 
 | 69 | Write(q.Y); | 
 
 
 
 
 | 70 | Write(q.Z); | 
 
 
 
 
 | 71 | Write(-q.W); | 
 
 
 
 
 | 72 | } | 
 
 
 
 
 | 73 |  | 
 
 
 
 
 | 74 | public void Write(Plane p) | 
 
 
 
 
 | 75 | { | 
 
 
 
 
 | 76 | Write(p.Normal); | 
 
 
 
 
 | 77 | Write(p.D); | 
 
 
 
 
 | 78 | } | 
 
 
 
 
 | 79 |  | 
 
 
 
 
 | 80 | public void Write(BoundingBox bbox) | 
 
 
 
 
 | 81 | { | 
 
 
 
 
 | 82 | Write(bbox.Min); | 
 
 
 
 
 | 83 | Write(bbox.Max); | 
 
 
 
 
 | 84 | } | 
 
 
 
 
 | 85 |  | 
 
 
 
 
 | 86 | public void Write(BoundingSphere bsphere) | 
 
 
 
 
 | 87 | { | 
 
 
 
 
 | 88 | Write(bsphere.Center); | 
 
 
 
 
 | 89 | Write(bsphere.Radius); | 
 
 
 
 
 | 90 | } | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | public void WriteMatrix4x3(Matrix m) | 
 
 
 
 
 | 93 | { | 
 
 
 
 
 | 94 | Write(m.M11); | 
 
 
 
 
 | 95 | Write(m.M12); | 
 
 
 
 
 | 96 | Write(m.M13); | 
 
 
 
 
 | 97 | Write(m.M21); | 
 
 
 
 
 | 98 | Write(m.M22); | 
 
 
 
 
 | 99 | Write(m.M23); | 
 
 
 
 
 | 100 | Write(m.M31); | 
 
 
 
 
 | 101 | Write(m.M32); | 
 
 
 
 
 | 102 | Write(m.M33); | 
 
 
 
 
 | 103 | Write(m.M41); | 
 
 
 
 
 | 104 | Write(m.M42); | 
 
 
 
 
 | 105 | Write(m.M43); | 
 
 
 
 
 | 106 | } | 
 
 
 
 
 | 107 |  | 
 
 
 
 
 | 108 | public void Write(short[] a) | 
 
 
 
 
 | 109 | { | 
 
 
 
 
 | 110 | foreach (short v in a) | 
 
 
 
 
 | 111 | Write(v); | 
 
 
 
 
 | 112 | } | 
 
 
 
 
 | 113 |  | 
 
 
 
 
 | 114 | public void Write(ushort[] a) | 
 
 
 
 
 | 115 | { | 
 
 
 
 
 | 116 | foreach (ushort v in a) | 
 
 
 
 
 | 117 | Write(v); | 
 
 
 
 
 | 118 | } | 
 
 
 
 
 | 119 |  | 
 
 
 
 
 | 120 | public void Write(int[] a) | 
 
 
 
 
 | 121 | { | 
 
 
 
 
 | 122 | foreach (int v in a) | 
 
 
 
 
 | 123 | Write(v); | 
 
 
 
 
 | 124 | } | 
 
 
 
 
 | 125 |  | 
 
 
 
 
 | 126 | public void Write(int[] v, int startIndex, int length) | 
 
 
 
 
 | 127 | { | 
 
 
 
 
 | 128 | for (int i = startIndex; i < startIndex + length; i++) | 
 
 
 
 
 | 129 | Write(v[i]); | 
 
 
 
 
 | 130 | } | 
 
 
 
 
 | 131 |  | 
 
 
 
 
 | 132 | public void Write(IEnumerable<float> a) | 
 
 
 
 
 | 133 | { | 
 
 
 
 
 | 134 | foreach (float v in a) | 
 
 
 
 
 | 135 | Write(v); | 
 
 
 
 
 | 136 | } | 
 
 
 
 
 | 137 |  | 
 
 
 
 
 | 138 | public void Write(IEnumerable<int> a) | 
 
 
 
 
 | 139 | { | 
 
 
 
 
 | 140 | foreach (int i in a) | 
 
 
 
 
 | 141 | Write(i); | 
 
 
 
 
 | 142 | } | 
 
 
 
 
 | 143 |  | 
 
 
 
 
 | 144 | public void Write(Color[] a) | 
 
 
 
 
 | 145 | { | 
 
 
 
 
 | 146 | foreach (Color v in a) | 
 
 
 
 
 | 147 | Write(v); | 
 
 
 
 
 | 148 | } | 
 
 
 
 
 | 149 |  | 
 
 
 
 
 | 150 | public void Write(IEnumerable<Vector2> a) | 
 
 
 
 
 | 151 | { | 
 
 
 
 
 | 152 | foreach (Vector2 v in a) | 
 
 
 
 
 | 153 | Write(v); | 
 
 
 
 
 | 154 | } | 
 
 
 
 
 | 155 |  | 
 
 
 
 
 | 156 | public void Write(IEnumerable<Vector3> a) | 
 
 
 
 
 | 157 | { | 
 
 
 
 
 | 158 | foreach (Vector3 v in a) | 
 
 
 
 
 | 159 | Write(v); | 
 
 
 
 
 | 160 | } | 
 
 
 
 
 | 161 |  | 
 
 
 
 
 | 162 | public void Write(IEnumerable<Plane> a) | 
 
 
 
 
 | 163 | { | 
 
 
 
 
 | 164 | foreach (Plane v in a) | 
 
 
 
 
 | 165 | Write(v); | 
 
 
 
 
 | 166 | } | 
 
 
 
 
 | 167 |  | 
 
 
 
 
 | 168 | public void Write(string s, int maxLength) | 
 
 
 
 
 | 169 | { | 
 
 
 
 
 | 170 | if (s == null) | 
 
 
 
 
 | 171 | { | 
 
 
 
 
 | 172 | Skip(maxLength); | 
 
 
 
 
 | 173 | return; | 
 
 
 
 
 | 174 | } | 
 
 
 
 
 | 175 |  | 
 
 
 
 
 | 176 | if (encoding.GetByteCount(s) > maxLength) | 
 
 
 
 
 | 177 | throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "The string '{0}' is too long (max length is {1})", s, maxLength)); | 
 
 
 
 
 | 178 |  | 
 
 
 
 
 | 179 | byte[] data = new byte[maxLength]; | 
 
 
 
 
 | 180 | encoding.GetBytes(s, 0, s.Length, data, 0); | 
 
 
 
 
 | 181 | Write(data); | 
 
 
 
 
 | 182 | } | 
 
 
 
 
 | 183 |  | 
 
 
 
 
 | 184 | public void WriteByte(int value) | 
 
 
 
 
 | 185 | { | 
 
 
 
 
 | 186 | if (value < byte.MinValue || byte.MaxValue < value) | 
 
 
 
 
 | 187 | throw new ArgumentOutOfRangeException("Value too large for Byte", "value"); | 
 
 
 
 
 | 188 |  | 
 
 
 
 
 | 189 | Write((byte)value); | 
 
 
 
 
 | 190 | } | 
 
 
 
 
 | 191 |  | 
 
 
 
 
 | 192 | public void WriteInt16(int value) | 
 
 
 
 
 | 193 | { | 
 
 
 
 
 | 194 | if (value < short.MinValue || short.MaxValue < value) | 
 
 
 
 
 | 195 | throw new ArgumentOutOfRangeException("Value too large for Int16", "value"); | 
 
 
 
 
 | 196 |  | 
 
 
 
 
 | 197 | Write((short)value); | 
 
 
 
 
 | 198 | } | 
 
 
 
 
 | 199 |  | 
 
 
 
 
 | 200 | public void WriteUInt16(int value) | 
 
 
 
 
 | 201 | { | 
 
 
 
 
 | 202 | if (value < 0 || value > UInt16.MaxValue) | 
 
 
 
 
 | 203 | throw new ArgumentOutOfRangeException("Value too large for UInt16", "value"); | 
 
 
 
 
 | 204 |  | 
 
 
 
 
 | 205 | Write((ushort)value); | 
 
 
 
 
 | 206 | } | 
 
 
 
 
 | 207 |  | 
 
 
 
 
 | 208 | public void Write(byte value, int count) | 
 
 
 
 
 | 209 | { | 
 
 
 
 
 | 210 | if (value == 0 && Position == OutStream.Length) | 
 
 
 
 
 | 211 | { | 
 
 
 
 
 | 212 | Seek(count, SeekOrigin.Current); | 
 
 
 
 
 | 213 | } | 
 
 
 
 
 | 214 | else | 
 
 
 
 
 | 215 | { | 
 
 
 
 
 | 216 | for (int i = 0; i < count; i++) | 
 
 
 
 
 | 217 | Write(value); | 
 
 
 
 
 | 218 | } | 
 
 
 
 
 | 219 | } | 
 
 
 
 
 | 220 |  | 
 
 
 
 
 | 221 | public void Skip(int length) | 
 
 
 
 
 | 222 | { | 
 
 
 
 
 | 223 | Position += length; | 
 
 
 
 
 | 224 | } | 
 
 
 
 
 | 225 |  | 
 
 
 
 
 | 226 | public override Stream BaseStream | 
 
 
 
 
 | 227 | { | 
 
 
 
 
 | 228 | get | 
 
 
 
 
 | 229 | { | 
 
 
 
 
 | 230 | // | 
 
 
 
 
 | 231 | // Note: return base OutStream directly instead of BaseStream to avoid | 
 
 
 
 
 | 232 | // flushing the stream. | 
 
 
 
 
 | 233 | // | 
 
 
 
 
 | 234 |  | 
 
 
 
 
 | 235 | return base.OutStream; | 
 
 
 
 
 | 236 | } | 
 
 
 
 
 | 237 | } | 
 
 
 
 
 | 238 |  | 
 
 
 
 
 | 239 | public void PushPosition(int newPosition) | 
 
 
 
 
 | 240 | { | 
 
 
 
 
 | 241 | positionStack.Push(Position); | 
 
 
 
 
 | 242 | Position = newPosition; | 
 
 
 
 
 | 243 | } | 
 
 
 
 
 | 244 |  | 
 
 
 
 
 | 245 | public void PopPosition() | 
 
 
 
 
 | 246 | { | 
 
 
 
 
 | 247 | Position = positionStack.Pop(); | 
 
 
 
 
 | 248 | } | 
 
 
 
 
 | 249 |  | 
 
 
 
 
 | 250 | public int Position | 
 
 
 
 
 | 251 | { | 
 
 
 
 
 | 252 | get | 
 
 
 
 
 | 253 | { | 
 
 
 
 
 | 254 | return (int)BaseStream.Position; | 
 
 
 
 
 | 255 | } | 
 
 
 
 
 | 256 | set | 
 
 
 
 
 | 257 | { | 
 
 
 
 
 | 258 | int currentPosition = (int)OutStream.Position; | 
 
 
 
 
 | 259 | int delta = value - currentPosition; | 
 
 
 
 
 | 260 |  | 
 
 
 
 
 | 261 | if (delta == 0) | 
 
 
 
 
 | 262 | return; | 
 
 
 
 
 | 263 |  | 
 
 
 
 
 | 264 | // | 
 
 
 
 
 | 265 | // Prevent changing the output stream position for small changes of position. | 
 
 
 
 
 | 266 | // This avoids flushing the write cache of the stream which results in poor perf. | 
 
 
 
 
 | 267 | // | 
 
 
 
 
 | 268 |  | 
 
 
 
 
 | 269 | if (0 < delta && delta <= 32 && Position == OutStream.Length) | 
 
 
 
 
 | 270 | OutStream.Write(padding, 0, delta); | 
 
 
 
 
 | 271 | else | 
 
 
 
 
 | 272 | OutStream.Position = value; | 
 
 
 
 
 | 273 | } | 
 
 
 
 
 | 274 | } | 
 
 
 
 
 | 275 |  | 
 
 
 
 
 | 276 | public void WriteAt(int position, int value) | 
 
 
 
 
 | 277 | { | 
 
 
 
 
 | 278 | PushPosition(position); | 
 
 
 
 
 | 279 | Write(value); | 
 
 
 
 
 | 280 | PopPosition(); | 
 
 
 
 
 | 281 | } | 
 
 
 
 
 | 282 |  | 
 
 
 
 
 | 283 | public void WriteAt(int position, short value) | 
 
 
 
 
 | 284 | { | 
 
 
 
 
 | 285 | PushPosition(position); | 
 
 
 
 
 | 286 | Write(value); | 
 
 
 
 
 | 287 | PopPosition(); | 
 
 
 
 
 | 288 | } | 
 
 
 
 
 | 289 |  | 
 
 
 
 
 | 290 | public int Align32() | 
 
 
 
 
 | 291 | { | 
 
 
 
 
 | 292 | int position = Utils.Align32(Position); | 
 
 
 
 
 | 293 | Position = position; | 
 
 
 
 
 | 294 | return position; | 
 
 
 
 
 | 295 | } | 
 
 
 
 
 | 296 | } | 
 
 
 
 
 | 297 | } |