1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
use super::blocks::{Block, *};
use super::common;
use crate::error::NifError;
use binread::{
    io::{Read, Seek},
    BinRead, BinResult, ReadOptions,
};
use std::io::SeekFrom;

pub fn parse_keys<R: Read + Seek, T: BinRead<Args = ()>>(
    reader: &mut R,
    options: &ReadOptions,
    args: (u32, Option<common::KeyType>),
) -> BinResult<Vec<common::Key<T>>> {
    if args.0 == 0 {
        return Ok(Vec::new());
    }
    let key_type = args.1.expect("num_keys was >0, key_type should exist");

    let mut keys = Vec::new();
    for _ in 0..args.0 {
        let key = common::Key::read_options(reader, options, (key_type,))?;
        keys.push(key);
    }

    Ok(keys)
}

pub fn parse_quat_keys<R: Read + Seek>(
    reader: &mut R,
    options: &ReadOptions,
    args: (u32, Option<common::KeyType>),
) -> BinResult<Vec<common::QuatKey>> {
    if args.0 == 0 {
        return Ok(Vec::new());
    }
    let key_type = args.1.expect("num_keys was >0, key_type should exist");
    if key_type == common::KeyType::XyzRotation {
        return Ok(Vec::new());
    }

    let mut keys = Vec::new();
    for _ in 0..args.0 {
        let key = common::QuatKey::read_options(reader, options, (key_type,))?;
        keys.push(key);
    }

    Ok(keys)
}

pub fn parse_version<R: Read + Seek>(
    reader: &mut R,
    options: &ReadOptions,
    a: (),
) -> BinResult<u32> {
    let version_str = parse_lf_terminated_string(reader, options, a)?;
    let version_split: Vec<u32> = version_str
        .split('.')
        .map(|s| s.parse())
        .filter_map(Result::ok)
        .collect::<Vec<u32>>();
    let version: u32 =
        version_split[0] << 24 | version_split[1] << 16 | version_split[2] << 8 | version_split[3];
    Ok(version)
}

pub fn parse_lf_terminated_string<R: Read + Seek>(
    reader: &mut R,
    _options: &ReadOptions,
    _: (),
) -> BinResult<String> {
    Ok(String::from_utf8_lossy(
        reader
            .bytes()
            .filter_map(Result::ok)
            .take_while(|&b| b != b'\n')
            .collect::<Vec<u8>>()
            .as_slice(),
    )
    .to_string())
}

pub fn parse_int_prefixed_string<R: Read + Seek>(
    reader: &mut R,
    options: &ReadOptions,
    _: (),
) -> BinResult<String> {
    let count = u32::read_options(reader, options, ())?;

    Ok(String::from_utf8_lossy(
        reader
            .bytes()
            .take(count as usize)
            .filter_map(Result::ok)
            .collect::<Vec<u8>>()
            .as_slice(),
    )
    .to_string())
}

pub fn parse_blocks<R: Read + Seek>(
    reader: &mut R,
    options: &ReadOptions,
    args: (Vec<String>, Vec<u16>),
) -> BinResult<Vec<Block>> {
    let mut blocks = Vec::new();

    for block_type_index in args.1 {
        match args.0.get(block_type_index as usize) {
            Some(block_type) => {
                // println!(
                //     "Reading block {} at {}",
                //     block_type,
                //     reader.seek(SeekFrom::Current(0))?
                // );

                let block = match block_type.as_ref() {
                    "NiObjectNET" => {
                        Block::NiObjectNET(NiObjectNET::read_options(reader, options, ())?)
                    }
                    "NiAvObject" => {
                        Block::NiAvObject(NiAvObject::read_options(reader, options, ())?)
                    }
                    "NiNode" => Block::NiNode(NiNode::read_options(reader, options, ())?),
                    "NiZBufferProperty" => Block::NiZBufferProperty(
                        NiZBufferProperty::read_options(reader, options, ())?,
                    ),
                    "NiVertexColorProperty" => Block::NiVertexColorProperty(
                        NiVertexColorProperty::read_options(reader, options, ())?,
                    ),
                    "NiTriShape" => {
                        Block::NiTriShape(NiTriShape::read_options(reader, options, ())?)
                    }
                    "NiStringExtraData" => Block::NiStringExtraData(
                        NiStringExtraData::read_options(reader, options, ())?,
                    ),
                    "NiTexturingProperty" => Block::NiTexturingProperty(
                        NiTexturingProperty::read_options(reader, options, ())?,
                    ),
                    "NiSourceTexture" => {
                        Block::NiSourceTexture(NiSourceTexture::read_options(reader, options, ())?)
                    }
                    "NiAlphaProperty" => {
                        Block::NiAlphaProperty(NiAlphaProperty::read_options(reader, options, ())?)
                    }
                    "NiMaterialProperty" => Block::NiMaterialProperty(
                        NiMaterialProperty::read_options(reader, options, ())?,
                    ),
                    "NiTriShapeData" => {
                        Block::NiTriShapeData(NiTriShapeData::read_options(reader, options, ())?)
                    }
                    "NiIntegerExtraData" => Block::NiIntegerExtraData(
                        NiIntegerExtraData::read_options(reader, options, ())?,
                    ),
                    "NiSpecularProperty" => Block::NiSpecularProperty(
                        NiSpecularProperty::read_options(reader, options, ())?,
                    ),
                    "NiSwitchNode" => {
                        Block::NiSwitchNode(NiSwitchNode::read_options(reader, options, ())?)
                    }
                    "NiLODNode" => Block::NiLODNode(NiLODNode::read_options(reader, options, ())?),
                    "NiRangeLODData" => {
                        Block::NiRangeLODData(NiRangeLODData::read_options(reader, options, ())?)
                    }
                    "NiBillboardNode" => {
                        Block::NiBillboardNode(NiBillboardNode::read_options(reader, options, ())?)
                    }
                    "NiCollisionData" => {
                        Block::NiCollisionData(NiCollisionData::read_options(reader, options, ())?)
                    }
                    "NiStencilProperty" => Block::NiStencilProperty(
                        NiStencilProperty::read_options(reader, options, ())?,
                    ),
                    "NiTimeController" => Block::NiTimeController(NiTimeController::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiInterpController" => Block::NiInterpController(
                        NiInterpController::read_options(reader, options, ())?,
                    ),
                    "NiSingleInterpController" => Block::NiSingleInterpController(
                        NiSingleInterpController::read_options(reader, options, ())?,
                    ),
                    "NiFloatInterpController" => Block::NiFloatInterpController(
                        NiFloatInterpController::read_options(reader, options, ())?,
                    ),
                    "NiAlphaController" => Block::NiAlphaController(
                        NiAlphaController::read_options(reader, options, ())?,
                    ),
                    "NiInterpolator" => {
                        Block::NiInterpolator(NiInterpolator::read_options(reader, options, ())?)
                    }
                    "NiKeyBasedInterpolator" => Block::NiKeyBasedInterpolator(
                        NiKeyBasedInterpolator::read_options(reader, options, ())?,
                    ),
                    "NiFloatInterpolator" => Block::NiFloatInterpolator(
                        NiFloatInterpolator::read_options(reader, options, ())?,
                    ),
                    "NiFloatData" => {
                        Block::NiFloatData(NiFloatData::read_options(reader, options, ())?)
                    }
                    "NiParticleSystem" => Block::NiParticleSystem(NiParticleSystem::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiPSysEmitterCtlr" => Block::NiPSysEmitterCtlr(
                        NiPSysEmitterCtlr::read_options(reader, options, ())?,
                    ),
                    "NiPSysUpdateCtlr" => Block::NiPSysUpdateCtlr(NiPSysUpdateCtlr::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiBoolInterpolator" => Block::NiBoolInterpolator(
                        NiBoolInterpolator::read_options(reader, options, ())?,
                    ),
                    "NiBoolData" => {
                        Block::NiBoolData(NiBoolData::read_options(reader, options, ())?)
                    }
                    "NiColorData" => {
                        Block::NiColorData(NiColorData::read_options(reader, options, ())?)
                    }
                    "NiPSysData" => {
                        Block::NiPSysData(NiPSysData::read_options(reader, options, ())?)
                    }
                    "NiPSysAgeDeathModifier" => Block::NiPSysAgeDeathModifier(
                        NiPSysAgeDeathModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysBoxEmitter" => Block::NiPSysBoxEmitter(NiPSysBoxEmitter::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiPSysSpawnModifier" => Block::NiPSysSpawnModifier(
                        NiPSysSpawnModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysGrowFadeModifier" => Block::NiPSysGrowFadeModifier(
                        NiPSysGrowFadeModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysColorModifier" => Block::NiPSysColorModifier(
                        NiPSysColorModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysRotationModifier" => Block::NiPSysRotationModifier(
                        NiPSysRotationModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysPositionModifier" => Block::NiPSysPositionModifier(
                        NiPSysPositionModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysBoundUpdateModifier" => Block::NiPSysBoundUpdateModifier(
                        NiPSysBoundUpdateModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysGravityModifier" => Block::NiPSysGravityModifier(
                        NiPSysGravityModifier::read_options(reader, options, ())?,
                    ),
                    "NiPSysColliderManager" => Block::NiPSysColliderManager(
                        NiPSysColliderManager::read_options(reader, options, ())?,
                    ),
                    "NiPSysPlanarCollider" => Block::NiPSysPlanarCollider(
                        NiPSysPlanarCollider::read_options(reader, options, ())?,
                    ),
                    "NiTransformController" => Block::NiTransformController(
                        NiTransformController::read_options(reader, options, ())?,
                    ),
                    "NiTransformInterpolator" => Block::NiTransformInterpolator(
                        NiTransformInterpolator::read_options(reader, options, ())?,
                    ),
                    "NiTransformData" => {
                        Block::NiTransformData(NiTransformData::read_options(reader, options, ())?)
                    }
                    "NiColorExtraData" => Block::NiColorExtraData(NiColorExtraData::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiFlipController" => Block::NiFlipController(NiFlipController::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiFloatExtraData" => Block::NiFloatExtraData(NiFloatExtraData::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiTextureTransformController" => Block::NiTextureTransformController(
                        NiTextureTransformController::read_options(reader, options, ())?,
                    ),
                    "NiPixelData" => {
                        Block::NiPixelData(NiPixelData::read_options(reader, options, ())?)
                    }
                    "NiVisController" => {
                        Block::NiVisController(NiVisController::read_options(reader, options, ())?)
                    }
                    "NiTextureEffect" => {
                        Block::NiTextureEffect(NiTextureEffect::read_options(reader, options, ())?)
                    }
                    "NiSourceCubeMap" => {
                        Block::NiSourceCubeMap(NiSourceCubeMap::read_options(reader, options, ())?)
                    }
                    "NiShadeProperty" => {
                        Block::NiShadeProperty(NiShadeProperty::read_options(reader, options, ())?)
                    }
                    "NiGeomMorpherController" => Block::NiGeomMorpherController(
                        NiGeomMorpherController::read_options(reader, options, ())?,
                    ),
                    "NiMorphData" => {
                        Block::NiMorphData(NiMorphData::read_options(reader, options, ())?)
                    }
                    "NiDitherProperty" => Block::NiDitherProperty(NiDitherProperty::read_options(
                        reader,
                        options,
                        (),
                    )?),
                    "NiMaterialColorController" => Block::NiMaterialColorController(
                        NiMaterialColorController::read_options(reader, options, ())?,
                    ),
                    "NiPoint3Interpolator" => Block::NiPoint3Interpolator(
                        NiPoint3Interpolator::read_options(reader, options, ())?,
                    ),
                    "NiPosData" => Block::NiPosData(NiPosData::read_options(reader, options, ())?),
                    "NiSkinInstance" => {
                        Block::NiSkinInstance(NiSkinInstance::read_options(reader, options, ())?)
                    }
                    "NiSkinData" => {
                        Block::NiSkinData(NiSkinData::read_options(reader, options, ())?)
                    }
                    "NiSkinPartition" => {
                        Block::NiSkinPartition(NiSkinPartition::read_options(reader, options, ())?)
                    }
                    "NiPathInterpolator" => Block::NiPathInterpolator(
                        NiPathInterpolator::read_options(reader, options, ())?,
                    ),
                    "NiTriStrips" => {
                        Block::NiTriStrips(NiTriStrips::read_options(reader, options, ())?)
                    }
                    "NiTriStripsData" => {
                        Block::NiTriStripsData(NiTriStripsData::read_options(reader, options, ())?)
                    }
                    "NiPSysMeshEmitter" => Block::NiPSysMeshEmitter(
                        NiPSysMeshEmitter::read_options(reader, options, ())?,
                    ),
                    "NiPSysCylinderEmitter" => Block::NiPSysCylinderEmitter(
                        NiPSysCylinderEmitter::read_options(reader, options, ())?,
                    ),
                    "NiPSysSphereEmitter" => Block::NiPSysSphereEmitter(
                        NiPSysSphereEmitter::read_options(reader, options, ())?,
                    ),
                    "NiPSysResetOnLoopCtlr" => Block::NiPSysResetOnLoopCtlr(
                        NiPSysResetOnLoopCtlr::read_options(reader, options, ())?,
                    ),
                    "NiDirectionalLight" => Block::NiDirectionalLight(
                        NiDirectionalLight::read_options(reader, options, ())?,
                    ),
                    "NiFloatsExtraData" => Block::NiFloatsExtraData(
                        NiFloatsExtraData::read_options(reader, options, ())?,
                    ),
                    _ => {
                        return Err(binread::Error::Custom {
                            pos: reader.seek(SeekFrom::Current(0))?,
                            err: Box::new(NifError::UnknownBlock(blocks.len(), block_type.clone())),
                        });
                    }
                };
                blocks.push(block);
            }
            None => {
                return Err(binread::Error::Custom {
                    pos: reader.seek(SeekFrom::Current(0))?,
                    err: Box::new(NifError::InvalidBlockTypeIndex),
                });
            }
        }
    }
    // println!("Finished reading at {}", reader.seek(SeekFrom::Current(0))?);

    Ok(blocks)
}