diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1b4661f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,42 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: +- package-ecosystem: nuget + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 999 + +- package-ecosystem: nuget + directory: "/LibForge/LibForge" + schedule: + interval: daily + open-pull-requests-limit: 999 + +- package-ecosystem: nuget + directory: "/LibForge/ForgeTool" + schedule: + interval: daily + open-pull-requests-limit: 999 + +- package-ecosystem: nuget + directory: "/LibForge/ForgeToolGUI" + schedule: + interval: daily + open-pull-requests-limit: 999 + +- package-ecosystem: nuget + directory: "/LibForge/LibForgeTests" + schedule: + interval: daily + open-pull-requests-limit: 999 + +- package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every day + interval: "daily" diff --git a/.github/workflows/LibForge-EXT.yml b/.github/workflows/LibForge-EXT.yml new file mode 100644 index 0000000..0bc9af8 --- /dev/null +++ b/.github/workflows/LibForge-EXT.yml @@ -0,0 +1,40 @@ +name: External Branch Build + +on: + push: + branches-ignore: + - master + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.3 + with: + vs-version: 17.3.3 + msbuild-architecture: x64 + + - name: Setup NuGet + uses: NuGet/setup-nuget@v1.1.1 + with: + nuget-version: latest + + - name: Clear NuGet cache + run: dotnet nuget locals all --clear + + - name: Restore NuGet Packages + working-directory: ./LibForge/ + run: nuget restore LibForge.sln + + - name: Build LibForge + working-directory: ./LibForge/ + run: msbuild LibForge.sln /p:Configuration=Release /p:DeployOnBuild=true diff --git a/.github/workflows/LibForge-main.yml b/.github/workflows/LibForge-main.yml new file mode 100644 index 0000000..081304a --- /dev/null +++ b/.github/workflows/LibForge-main.yml @@ -0,0 +1,70 @@ +name: Main Compilation + +on: + push: + branches: [ "master" ] + +env: + version: 0.1.${{ github.run_number }} + +jobs: + build: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.3 + with: + vs-version: 17.3.3 + msbuild-architecture: x64 + + - name: Setup NuGet + uses: NuGet/setup-nuget@v1.1.1 + with: + nuget-version: latest + + - name: Clear NuGet cache + run: dotnet nuget locals all --clear + + - name: Restore NuGet Packages + working-directory: ./LibForge/ + run: nuget restore LibForge.sln + + - name: Build LibForge + working-directory: ./LibForge/ + run: msbuild LibForge.sln /p:Configuration=Release /p:DeployOnBuild=true + + - name: Zip LibForge + uses: TheDoctor0/zip-release@main + with: + type: 'zip' + path: .\LibForge\LibForge\bin\Release\net6.0\* + filename: LibForge-${{ env.version }}.zip + + - name: Zip ForgeTool + uses: TheDoctor0/zip-release@main + with: + type: 'zip' + path: .\LibForge\ForgeTool\bin\Release\net6.0\* + filename: ForgeTool-${{ env.version }}.zip + + - name: Zip ForgeToolGUI + uses: TheDoctor0/zip-release@main + with: + type: 'zip' + path: .\LibForge\ForgeToolGUI\bin\Release\net6.0-windows\* + filename: ForgeToolGUI-${{ env.version }}.zip + + - name: GH Release + uses: ncipollo/release-action@v1 + with: + artifacts: "LibForge-${{ env.version }}.zip,ForgeTool-${{ env.version }}.zip,ForgeToolGUI-${{ env.version }}.zip" + generateReleaseNotes: true + name: Release ${{ env.version }} + tag: ${{ env.version }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/010/ForgeMidi.bt b/010/ForgeMidi.bt index e14de17..fd83998 100644 --- a/010/ForgeMidi.bt +++ b/010/ForgeMidi.bt @@ -1,637 +1,637 @@ -#include "common.bt" - -LittleEndian(); - -// Forge MIDI -typedef enum { - NOTE_OFF = 0x8, - NOTE_ON = 0x9, - POLY_PRS = 0xA, - CTRL_CHG = 0xB, - PRGM_CHG = 0xC, - CHAN_PRS = 0xD, - PITCH_BD = 0xE -} msg_type; - -typedef enum { - Text = 0x1, - TrackName = 0x3, - Lyric = 0x5 -} str_type; - -typedef struct { - char channel : 4; - msg_type type : 4; -} msg_type_chan; - -typedef int tick_t; -string tick_t_read(tick_t tick){ - string result; - SPrintf(result, "%d:%d", tick / 480, tick % 480); - return result; -} - -typedef struct { - char note; - char velocity; -} M_NOTE_ON; - -typedef struct { - char note; - char velocity; -} M_NOTE_OFF; - -typedef struct { - char unk[2]; -} M_POLY_PRS; - -typedef struct { - char controller; - char amt; -} M_CTRL_CHG; - -typedef struct { - char unk[2]; -} M_PRGM_CHG; - -typedef struct { - char unk[2]; -} M_CHAN_PRS; -typedef struct { - char lsb; - char msb; -} M_PITCH_BD; - -typedef unsigned char int24[3]; -string int24_read(int24 v) -{ - int val = ((int)v[0] << 16) | ((int)v[2] << 8) | v[1]; - string ret; - SPrintf(ret, "%d", val); - return ret; -} - -typedef struct { - tick_t tick; - char kind; - if(kind == 1){ - msg_type_chan tc; - if(tc.type > 9){ - Printf("0x%X: Type %d\n", FTell(), tc.type); - } - switch(tc.type){ - case NOTE_OFF: - M_NOTE_OFF msg; - break; - case NOTE_ON: - M_NOTE_ON msg; - break; - case POLY_PRS: - M_POLY_PRS msg; - break; - case CTRL_CHG: - M_CTRL_CHG msg; - break; - case PRGM_CHG: - M_PRGM_CHG msg; - break; - case CHAN_PRS: - M_CHAN_PRS msg; - break; - case PITCH_BD: - M_PITCH_BD msg; - break; - } - } - else if(kind == 2) { - // weird: MSB first, then remaining bytes in LE - int24 tempo; - } - else if(kind == 4) { - char num; - char denom; - char unused; - } - else if(kind == 8) { - // I think this is 1 -> text event, 3 -> track name, 5 -> lyric - str_type string_type; - int16 string_offset; - } - else { - local string tmp; - SPrintf(tmp, "Unknown kind %d", kind); - Assert(false, tmp); - } -} midi_message; - -typedef struct { - uint tick; - PSTR str; -} TickedInfo_String; -string TickedInfo_String_READ(TickedInfo_String& l){ - return PSTR_READ(l.str); -} - -typedef struct { - PSTR track_name; - int num_tickedInfo_String; - if(num_tickedInfo_String > 0) - TickedInfo_String lyrics[num_tickedInfo_String]; - int unknown; - int unknown_2; - char unkFlag; -} TrackInfo; -string TrackInfo_READ(TrackInfo& t){ - string ret; - SPrintf(ret, "%s (%d, %d, %d)", PSTR_READ(t.track_name), t.unknown, t.unknown_2, t.unkFlag); - return ret; -} - -typedef struct { - tick_t tick; - int data; -} TickedInfo_int; - -typedef struct { - tick_t tick; - float data; -} TickedInfo_float; - -typedef struct { - tick_t fill_start_tick; - tick_t fill_end_tick; - char is_BRE; -} FillExtent; - -typedef struct { - int num_fills; - if(num_fills > 0) - TickedInfo_int fills[num_fills]; - int num_fill_extents; - if(num_fill_extents > 0) - FillExtent fill_extents[num_fill_extents]; -} DrumFillInfo; - -typedef struct { - float start_millis; - tick_t start_ticks; - short length_millis; - short length_ticks; - struct { - int lane_1 : 1; - int lane_2 : 1; - int lane_3 : 1; - int lane_4 : 1; - int lane_5 : 1; - int additional_real_keys_lanes : 27; - } lanes ; - char is_hopo; - Assert(is_hopo == 0 || is_hopo == 1); - char no_tail; - Assert(no_tail == 0 || no_tail == 1); - char flag3, flag4, flag5, flag6; -// Probably more flags for rbmid_pc -// Assert(unknown == 0 || unknown == 1); -} GameGem; -string GEM_read(GameGem& gem){ - string ret; - SPrintf(ret, "%f", gem.start_millis/1000); - return ret; -} - -typedef struct { - int unknown_aa; - int num_gems; - if(num_gems) - GameGem gem[num_gems]; -} GameGemList; - -typedef struct { - int num_difficulties; - GameGemList gemLists[num_difficulties]; - int end; -} GameGemDB; - -typedef struct { - PSTR track_name; - GameGemDB animation; -} FakeTrack; - -typedef struct { - int num_pro_markers; - struct { - tick_t tick; - struct { - int unk : 1; - int unk2: 1; - int PRO_YELLOW : 1; - int PRO_BLUE : 1; - int PRO_GREEN : 1; - } flags; - } markers[num_pro_markers]; // same as TickedInfo_int - int num_fill_extents; - if(num_fill_extents > 0) - FillExtent fill_extents[num_fill_extents]; - int unk; -} DrumMap; - -typedef struct { - int difficulties; - if(difficulties > 0){ - struct { - int32 num_markers; - if(num_markers > 0){ - struct{ - tick_t StartTick; - tick_t EndTick; - struct { - int Glissando : 1; - int Trill : 1; - int Roll_1Lane : 1; - int Roll_2Lane : 1; - int Unk : 28; - } flags; - } markers[num_markers]; - } - } data2[difficulties]; - } -} LANEMARKER; - -typedef struct { - int difficulties; - if(difficulties > 0) - struct{ - int count; - struct { - tick_t Start; - tick_t End; - int LowFret; - int HighFret; - } trills[count]; - } difficulty[difficulties]; -} GTRTRILLS; - -typedef struct { - int num_difficulties; - struct { - int num_mixes; - if(num_mixes) - TickedInfo_String mix[num_mixes]; - } drum_mixes[num_difficulties]; -} DRUMMIX; - -typedef struct { - int num_difficulties; - struct { - int num_section_types; - // 1st element: Overdrive sections - // 2nd element: Solo sections - struct { - int num_sections; - struct { - tick_t start_ticks; - tick_t duration_ticks; - } sections[num_sections]; - } section_types[num_section_types]; - } difficulties[num_difficulties]; -} PhraseDB; - -typedef struct { - float start_ms; - float length; - tick_t start_tick; - tick_t length_ticks; - int unk_start_note; - int unk_end_note; - char is_phrase; - char is_overdrive; - char unused[9]; - float LowNote; - float HighNote; - char UnknownCount; - char UnknownFlag; - char unused2[8]; -} PHRASE; - -typedef struct { - int num_phrase_markers; - PHRASE phrase_markers[num_phrase_markers]; - int num_phrase_markers_2; - PHRASE phrase_markers_2[num_phrase_markers_2]; - int num_notes; - struct { - int type; - int midi_note_start; - int midi_note_end; // same as start unless portamento - float start_ms; - tick_t start; - float length; - ushort length_ticks; - PSTR lyric; // empty string on portamento, symbols always stripped - char IsLastNoteInPhrase; - char UnkZero; - char Unpitched; - char UnpitchedGenerous; - char RangeDivider; // always 0? - char TugOfWarBitmask; // Not a flag? - char IsPortamento; - char UnkFlag; // always 0? - char UnkFlag; // always 1? - } vocal_notes[num_notes]; - int num_percussions; - tick_t percussions[num_percussions]; - int num_tacets; - struct { - float StartMillis; - float EndMillis; - }tacets[num_tacets]; -} VOCALTRACK; - -typedef struct { - int num_maps; - struct { - float StartTime; - int map; - } hand_maps[num_maps]; -} HANDMAP; - -typedef struct { - int num_hand_positions; - struct { - float StartTime; - float Length; - int position; - char unk; - } hand_pos_events[num_hand_positions]; -} HANDPOS; - -typedef struct { - int count; - struct { - float Time; - int Map; - } maps[count]; -} STRUMMAP; -string STRUMMAP_read(STRUMMAP& u) -{ - string ret; - SPrintf(ret, "%d", u.count); - return ret; -} - -// Used during guitar solos. Maybe for freestyle? -typedef struct { - tick_t start; - tick_t end; - // Seem to be notes from MIDI 0-11, and then 12-23 - // This is the offset to those notes - int note_offset; -} MARKUP_SOLO_NOTES; - -typedef struct { - tick_t start; - tick_t end; -} TWOTICKS; - -// Notes are taken relative to C, mod 12. So 0 => C, 2 => D, etc. -typedef struct { - tick_t start; - tick_t end; - int notes_in_chord; - Assert(notes_in_chord <= 12, "Only 12 notes in an octave"); - int notes[notes_in_chord]; -} VocalImprovSingleChord; - -typedef struct { - int num_markup_chords_1; - VocalImprovSingleChord markup_chords[num_markup_chords_1]; -} VocalImprovChordInfo; - -typedef struct { - int count; - MARKUP_SOLO_NOTES extents[count]; -} ImprovSoloCueExtentVector; - -typedef struct { - int count; - TWOTICKS loop_map[count]; -} ImprovSoloCueLoopMappingVector; - -typedef struct { - ImprovSoloCueExtentVector loopExtents; - ImprovSoloCueLoopMappingVector loopMap; -} ImprovSoloCueInfo; - -typedef struct { - int count; - MARKUP_SOLO_NOTES loops[count]; -} RBLoopDefnVector; - -typedef struct { - char unk; - int unk2; - int num_events; - midi_message events[num_events]; - int num_strs; - PSTR strings[num_strs]; -} MIDITRACK; - -typedef int tempo_t; -string tempo_t_read(tempo_t tempo){ - string result; - SPrintf(result, "%f", 60000000.0 / tempo); - return result; -} -typedef struct { - float time; - tick_t tick; - tempo_t tempo; -} TEMPO; - -typedef struct { - int measure; - tick_t tick; - int16 numerator; - int16 denominator; -} TIMESIG; -string TIMESIG_read(TIMESIG& t){ - string ret; - SPrintf(ret, "%s : %d/%d, %d", tick_t_read(t.tick), t.numerator, t.denominator, t.measure); - return ret; -} - -typedef struct { - tick_t tick; - int is_downbeat; -} BEAT; -// File starts here! - -typedef struct { - int num_beatmatch_sections; - struct { - int unk_zero; - PSTR beatmatch_section; - tick_t unk; - tick_t unk; - } beatmatch_section[num_beatmatch_sections]; - int unk_vrevent_count; - struct { - int unk; - float unk; - float unk; - tick_t unk; - tick_t unk; - int unk; - } unk_struct[unk_vrevent_count]; - int unk_vrevent_count2; - struct { - int unk; - PSTR name; - tick_t when; - } unk_struct2[unk_vrevent_count2]; - int unk_vrevent_count3; - struct { - int unk; - PSTR exsandohs; - tick_t tick_1; - tick_t tick_2; - char flags[7]; - int neg_one; - } unk_struct3[unk_vrevent_count3]; - int unk_vrevent_count4; - struct { - int unk; - PSTR name; - tick_t StartTick; - tick_t EndTick; - } unk_struct4[unk_vrevent_count4]; - int unk_vrevent_count5; - struct { - int unk; - PSTR name; - int num_exsohs; - PSTR exsohs[num_exsohs]; - tick_t tick_1; - tick_t tick_2; - char unk; - } unk_struct5[unk_vrevent_count5]; - int unk_vrevent_count5; - tick_t unk_tick[unk_vrevent_count5]; - int unk_zero; - int unk_vrevent_count6; - struct { - tick_t tick; - int unk; - } unk_struct6[unk_vrevent_count6]; -} RBVREVENTS; -typedef struct { - int revision; - Assert(revision == 2, "Unknown MidiFileResource revision"); - struct { - tick_t LastMarkupEventTick; - int num_midi_tracks; - MIDITRACK tracks[num_midi_tracks]; - } MidiFile; - struct { - tick_t SomeLastTick; - uint NumMeasures; - uint unknown[6]; - tick_t SomeLastTickMinus1; - float unk_MultiTempoTempoMap_floats[4]; - int num_tempos; - TEMPO tempos[num_tempos]; - int num_time_sigs; - TIMESIG time_signatures[num_time_sigs]; - int num_beats; - BEAT beats[num_beats]; - int num_song_sections; // always 0? - int num_midi_track_names; - PSTR midi_track_names[num_midi_track_names]; - } SongMaps; -} MidiFileResource; - -if(ReadInt() > 0x2){ // rbmid_ps4/pc - int format; - int num_track_info; - TrackInfo trackInfo[num_track_info] ; - int num_fill_tracks; - Assert(num_fill_tracks == num_track_info); - DrumFillInfo drum_fills[num_fill_tracks] ; - int num_anim_tracks; - FakeTrack anims[num_anim_tracks] ; - int num_marker_tracks; - Assert(num_marker_tracks == num_track_info); - DrumMap pro_markers[num_marker_tracks] ; - int num_lane_markers; - Assert(num_lane_markers == num_track_info); - LANEMARKER lane_markers[num_lane_markers] ; - int num_gtr_trills; - Assert(num_gtr_trills == num_track_info); - GTRTRILLS gtr_trills[num_gtr_trills] ; - int num_drum_mixes; - Assert(num_drum_mixes == num_track_info); - DRUMMIX drum_mixes[num_drum_mixes] ; - int num_gem_tracks; - Assert(num_gem_tracks == num_track_info); - GameGemDB gems[num_gem_tracks] ; - int num_sections; - Assert(num_sections == num_track_info); - PhraseDB overdrive_solo_sections[num_sections] ; - int num_vocal_tracks; - VOCALTRACK vocal_tracks[num_vocal_tracks]; - int num_unk_float_data; - TickedInfo_float unk_float_data[num_unk_float_data]; - int num_unk_structs; - struct { - tick_t unk_tick; - float unk_float; - } unk_structs[num_unk_structs]; - int num_vocaltrack_ranges; - struct { - float StartMillis; - tick_t StartTicks; - float LowNote; - float HighNote; - } VocalTrackRange[num_vocaltrack_ranges]; - int what; - if (format < 0xC) - int what_2; - int num_tracks_repeat; - Assert(num_tracks_repeat == num_track_info); - tick_t FinalTick; - if(format == 0x2f){ - tick_t UnknownTick; - } - char what; - float preview_start_ms; - float preview_end_ms; - //Assert(preview_end_ms > preview_start_ms, "preview_end_ms > preview_start_ms"); - int num_guitar_handmap_tracks; - Assert(num_guitar_handmap_tracks == num_track_info); - HANDMAP guitar_handmap_tracks[num_guitar_handmap_tracks]; - int num_left_hand_tracks; - Assert(num_left_hand_tracks == num_track_info); - HANDPOS left_hand_tracks[num_left_hand_tracks]; - int num_strummap_tracks; - Assert(num_strummap_tracks == num_track_info); - STRUMMAP strum_maps[num_strummap_tracks]; - - // Begin markup section - if (format >= 0x7) - ImprovSoloCueInfo cueInfo1; - if (format >= 0x8) - VocalImprovChordInfo voxChordInfo; - if (format >= 0xA) - RBLoopDefnVector loopDefns; - if (format >= 0xC) - ImprovSoloCueInfo cueInfo2; - - if(format == 0x2f) { // RBVR Specific section - RBVREVENTS vr_events; - } - MidiFileResource midiFileResource; - // File End -} -else if(ReadInt() == 0x2){ // mid_ps4/pc - MidiFileResource midiFileResource; +#include "common.bt" + +LittleEndian(); + +// Forge MIDI +typedef enum { + NOTE_OFF = 0x8, + NOTE_ON = 0x9, + POLY_PRS = 0xA, + CTRL_CHG = 0xB, + PRGM_CHG = 0xC, + CHAN_PRS = 0xD, + PITCH_BD = 0xE +} msg_type; + +typedef enum { + Text = 0x1, + TrackName = 0x3, + Lyric = 0x5 +} str_type; + +typedef struct { + char channel : 4; + msg_type type : 4; +} msg_type_chan; + +typedef int tick_t; +string tick_t_read(tick_t tick){ + string result; + SPrintf(result, "%d:%d", tick / 480, tick % 480); + return result; +} + +typedef struct { + char note; + char velocity; +} M_NOTE_ON; + +typedef struct { + char note; + char velocity; +} M_NOTE_OFF; + +typedef struct { + char unk[2]; +} M_POLY_PRS; + +typedef struct { + char controller; + char amt; +} M_CTRL_CHG; + +typedef struct { + char unk[2]; +} M_PRGM_CHG; + +typedef struct { + char unk[2]; +} M_CHAN_PRS; +typedef struct { + char lsb; + char msb; +} M_PITCH_BD; + +typedef unsigned char int24[3]; +string int24_read(int24 v) +{ + int val = ((int)v[0] << 16) | ((int)v[2] << 8) | v[1]; + string ret; + SPrintf(ret, "%d", val); + return ret; +} + +typedef struct { + tick_t tick; + char kind; + if(kind == 1){ + msg_type_chan tc; + if(tc.type > 9){ + Printf("0x%X: Type %d\n", FTell(), tc.type); + } + switch(tc.type){ + case NOTE_OFF: + M_NOTE_OFF msg; + break; + case NOTE_ON: + M_NOTE_ON msg; + break; + case POLY_PRS: + M_POLY_PRS msg; + break; + case CTRL_CHG: + M_CTRL_CHG msg; + break; + case PRGM_CHG: + M_PRGM_CHG msg; + break; + case CHAN_PRS: + M_CHAN_PRS msg; + break; + case PITCH_BD: + M_PITCH_BD msg; + break; + } + } + else if(kind == 2) { + // weird: MSB first, then remaining bytes in LE + int24 tempo; + } + else if(kind == 4) { + char num; + char denom; + char unused; + } + else if(kind == 8) { + // I think this is 1 -> text event, 3 -> track name, 5 -> lyric + str_type string_type; + int16 string_offset; + } + else { + local string tmp; + SPrintf(tmp, "Unknown kind %d", kind); + Assert(false, tmp); + } +} midi_message; + +typedef struct { + uint tick; + PSTR str; +} TickedInfo_String; +string TickedInfo_String_READ(TickedInfo_String& l){ + return PSTR_READ(l.str); +} + +typedef struct { + PSTR track_name; + int num_tickedInfo_String; + if(num_tickedInfo_String > 0) + TickedInfo_String lyrics[num_tickedInfo_String]; + int unknown; + int unknown_2; + char unkFlag; +} TrackInfo; +string TrackInfo_READ(TrackInfo& t){ + string ret; + SPrintf(ret, "%s (%d, %d, %d)", PSTR_READ(t.track_name), t.unknown, t.unknown_2, t.unkFlag); + return ret; +} + +typedef struct { + tick_t tick; + int data; +} TickedInfo_int; + +typedef struct { + tick_t tick; + float data; +} TickedInfo_float; + +typedef struct { + tick_t fill_start_tick; + tick_t fill_end_tick; + char is_BRE; +} FillExtent; + +typedef struct { + int num_fills; + if(num_fills > 0) + TickedInfo_int fills[num_fills]; + int num_fill_extents; + if(num_fill_extents > 0) + FillExtent fill_extents[num_fill_extents]; +} DrumFillInfo; + +typedef struct { + float start_millis; + tick_t start_ticks; + short length_millis; + short length_ticks; + struct { + int lane_1 : 1; + int lane_2 : 1; + int lane_3 : 1; + int lane_4 : 1; + int lane_5 : 1; + int additional_real_keys_lanes : 27; + } lanes ; + char is_hopo; + Assert(is_hopo == 0 || is_hopo == 1); + char no_tail; + Assert(no_tail == 0 || no_tail == 1); + char flag3, flag4, flag5, flag6; +// Probably more flags for rbmid_pc +// Assert(unknown == 0 || unknown == 1); +} GameGem; +string GEM_read(GameGem& gem){ + string ret; + SPrintf(ret, "%f", gem.start_millis/1000); + return ret; +} + +typedef struct { + int unknown_aa; + int num_gems; + if(num_gems) + GameGem gem[num_gems]; +} GameGemList; + +typedef struct { + int num_difficulties; + GameGemList gemLists[num_difficulties]; + int end; +} GameGemDB; + +typedef struct { + PSTR track_name; + GameGemDB animation; +} FakeTrack; + +typedef struct { + int num_pro_markers; + struct { + tick_t tick; + struct { + int unk : 1; + int unk2: 1; + int PRO_YELLOW : 1; + int PRO_BLUE : 1; + int PRO_GREEN : 1; + } flags; + } markers[num_pro_markers]; // same as TickedInfo_int + int num_fill_extents; + if(num_fill_extents > 0) + FillExtent fill_extents[num_fill_extents]; + int unk; +} DrumMap; + +typedef struct { + int difficulties; + if(difficulties > 0){ + struct { + int32 num_markers; + if(num_markers > 0){ + struct{ + tick_t StartTick; + tick_t EndTick; + struct { + int Glissando : 1; + int Trill : 1; + int Roll_1Lane : 1; + int Roll_2Lane : 1; + int Unk : 28; + } flags; + } markers[num_markers]; + } + } data2[difficulties]; + } +} LANEMARKER; + +typedef struct { + int difficulties; + if(difficulties > 0) + struct{ + int count; + struct { + tick_t Start; + tick_t End; + int LowFret; + int HighFret; + } trills[count]; + } difficulty[difficulties]; +} GTRTRILLS; + +typedef struct { + int num_difficulties; + struct { + int num_mixes; + if(num_mixes) + TickedInfo_String mix[num_mixes]; + } drum_mixes[num_difficulties]; +} DRUMMIX; + +typedef struct { + int num_difficulties; + struct { + int num_section_types; + // 1st element: Overdrive sections + // 2nd element: Solo sections + struct { + int num_sections; + struct { + tick_t start_ticks; + tick_t duration_ticks; + } sections[num_sections]; + } section_types[num_section_types]; + } difficulties[num_difficulties]; +} PhraseDB; + +typedef struct { + float start_ms; + float length; + tick_t start_tick; + tick_t length_ticks; + int unk_start_note; + int unk_end_note; + char is_phrase; + char is_overdrive; + char unused[9]; + float LowNote; + float HighNote; + char UnknownCount; + char UnknownFlag; + char unused2[8]; +} PHRASE; + +typedef struct { + int num_phrase_markers; + PHRASE phrase_markers[num_phrase_markers]; + int num_phrase_markers_2; + PHRASE phrase_markers_2[num_phrase_markers_2]; + int num_notes; + struct { + int type; + int midi_note_start; + int midi_note_end; // same as start unless portamento + float start_ms; + tick_t start; + float length; + ushort length_ticks; + PSTR lyric; // empty string on portamento, symbols always stripped + char IsLastNoteInPhrase; + char UnkZero; + char Unpitched; + char UnpitchedGenerous; + char RangeDivider; // always 0? + char TugOfWarBitmask; // Not a flag? + char IsPortamento; + char UnkFlag; // always 0? + char UnkFlag; // always 1? + } vocal_notes[num_notes]; + int num_percussions; + tick_t percussions[num_percussions]; + int num_tacets; + struct { + float StartMillis; + float EndMillis; + }tacets[num_tacets]; +} VOCALTRACK; + +typedef struct { + int num_maps; + struct { + float StartTime; + int map; + } hand_maps[num_maps]; +} HANDMAP; + +typedef struct { + int num_hand_positions; + struct { + float StartTime; + float Length; + int position; + char unk; + } hand_pos_events[num_hand_positions]; +} HANDPOS; + +typedef struct { + int count; + struct { + float Time; + int Map; + } maps[count]; +} STRUMMAP; +string STRUMMAP_read(STRUMMAP& u) +{ + string ret; + SPrintf(ret, "%d", u.count); + return ret; +} + +// Used during guitar solos. Maybe for freestyle? +typedef struct { + tick_t start; + tick_t end; + // Seem to be notes from MIDI 0-11, and then 12-23 + // This is the offset to those notes + int note_offset; +} MARKUP_SOLO_NOTES; + +typedef struct { + tick_t start; + tick_t end; +} TWOTICKS; + +// Notes are taken relative to C, mod 12. So 0 => C, 2 => D, etc. +typedef struct { + tick_t start; + tick_t end; + int notes_in_chord; + Assert(notes_in_chord <= 12, "Only 12 notes in an octave"); + int notes[notes_in_chord]; +} VocalImprovSingleChord; + +typedef struct { + int num_markup_chords_1; + VocalImprovSingleChord markup_chords[num_markup_chords_1]; +} VocalImprovChordInfo; + +typedef struct { + int count; + MARKUP_SOLO_NOTES extents[count]; +} ImprovSoloCueExtentVector; + +typedef struct { + int count; + TWOTICKS loop_map[count]; +} ImprovSoloCueLoopMappingVector; + +typedef struct { + ImprovSoloCueExtentVector loopExtents; + ImprovSoloCueLoopMappingVector loopMap; +} ImprovSoloCueInfo; + +typedef struct { + int count; + MARKUP_SOLO_NOTES loops[count]; +} RBLoopDefnVector; + +typedef struct { + char unk; + int unk2; + int num_events; + midi_message events[num_events]; + int num_strs; + PSTR strings[num_strs]; +} MIDITRACK; + +typedef int tempo_t; +string tempo_t_read(tempo_t tempo){ + string result; + SPrintf(result, "%f", 60000000.0 / tempo); + return result; +} +typedef struct { + float time; + tick_t tick; + tempo_t tempo; +} TEMPO; + +typedef struct { + int measure; + tick_t tick; + int16 numerator; + int16 denominator; +} TIMESIG; +string TIMESIG_read(TIMESIG& t){ + string ret; + SPrintf(ret, "%s : %d/%d, %d", tick_t_read(t.tick), t.numerator, t.denominator, t.measure); + return ret; +} + +typedef struct { + tick_t tick; + int is_downbeat; +} BEAT; +// File starts here! + +typedef struct { + int num_beatmatch_sections; + struct { + int unk_zero; + PSTR beatmatch_section; + tick_t unk; + tick_t unk; + } beatmatch_section[num_beatmatch_sections]; + int unk_vrevent_count; + struct { + int unk; + float unk; + float unk; + tick_t unk; + tick_t unk; + int unk; + } unk_struct[unk_vrevent_count]; + int unk_vrevent_count2; + struct { + int unk; + PSTR name; + tick_t when; + } unk_struct2[unk_vrevent_count2]; + int unk_vrevent_count3; + struct { + int unk; + PSTR exsandohs; + tick_t tick_1; + tick_t tick_2; + char flags[7]; + int neg_one; + } unk_struct3[unk_vrevent_count3]; + int unk_vrevent_count4; + struct { + int unk; + PSTR name; + tick_t StartTick; + tick_t EndTick; + } unk_struct4[unk_vrevent_count4]; + int unk_vrevent_count5; + struct { + int unk; + PSTR name; + int num_exsohs; + PSTR exsohs[num_exsohs]; + tick_t tick_1; + tick_t tick_2; + char unk; + } unk_struct5[unk_vrevent_count5]; + int unk_vrevent_count5; + tick_t unk_tick[unk_vrevent_count5]; + int unk_zero; + int unk_vrevent_count6; + struct { + tick_t tick; + int unk; + } unk_struct6[unk_vrevent_count6]; +} RBVREVENTS; +typedef struct { + int revision; + Assert(revision == 2, "Unknown MidiFileResource revision"); + struct { + tick_t LastMarkupEventTick; + int num_midi_tracks; + MIDITRACK tracks[num_midi_tracks]; + } MidiFile; + struct { + tick_t SomeLastTick; + uint NumMeasures; + uint unknown[6]; + tick_t SomeLastTickMinus1; + float unk_MultiTempoTempoMap_floats[4]; + int num_tempos; + TEMPO tempos[num_tempos]; + int num_time_sigs; + TIMESIG time_signatures[num_time_sigs]; + int num_beats; + BEAT beats[num_beats]; + int num_song_sections; // always 0? + int num_midi_track_names; + PSTR midi_track_names[num_midi_track_names]; + } SongMaps; +} MidiFileResource; + +if(ReadInt() > 0x2){ // rbmid_ps4/pc + int format; + int num_track_info; + TrackInfo trackInfo[num_track_info] ; + int num_fill_tracks; + Assert(num_fill_tracks == num_track_info); + DrumFillInfo drum_fills[num_fill_tracks] ; + int num_anim_tracks; + FakeTrack anims[num_anim_tracks] ; + int num_marker_tracks; + Assert(num_marker_tracks == num_track_info); + DrumMap pro_markers[num_marker_tracks] ; + int num_lane_markers; + Assert(num_lane_markers == num_track_info); + LANEMARKER lane_markers[num_lane_markers] ; + int num_gtr_trills; + Assert(num_gtr_trills == num_track_info); + GTRTRILLS gtr_trills[num_gtr_trills] ; + int num_drum_mixes; + Assert(num_drum_mixes == num_track_info); + DRUMMIX drum_mixes[num_drum_mixes] ; + int num_gem_tracks; + Assert(num_gem_tracks == num_track_info); + GameGemDB gems[num_gem_tracks] ; + int num_sections; + Assert(num_sections == num_track_info); + PhraseDB overdrive_solo_sections[num_sections] ; + int num_vocal_tracks; + VOCALTRACK vocal_tracks[num_vocal_tracks]; + int num_unk_float_data; + TickedInfo_float unk_float_data[num_unk_float_data]; + int num_unk_structs; + struct { + tick_t unk_tick; + float unk_float; + } unk_structs[num_unk_structs]; + int num_vocaltrack_ranges; + struct { + float StartMillis; + tick_t StartTicks; + float LowNote; + float HighNote; + } VocalTrackRange[num_vocaltrack_ranges]; + int what; + if (format < 0xC) + int what_2; + int num_tracks_repeat; + Assert(num_tracks_repeat == num_track_info); + tick_t FinalTick; + if(format == 0x2f){ + tick_t UnknownTick; + } + char what; + float preview_start_ms; + float preview_end_ms; + //Assert(preview_end_ms > preview_start_ms, "preview_end_ms > preview_start_ms"); + int num_guitar_handmap_tracks; + Assert(num_guitar_handmap_tracks == num_track_info); + HANDMAP guitar_handmap_tracks[num_guitar_handmap_tracks]; + int num_left_hand_tracks; + Assert(num_left_hand_tracks == num_track_info); + HANDPOS left_hand_tracks[num_left_hand_tracks]; + int num_strummap_tracks; + Assert(num_strummap_tracks == num_track_info); + STRUMMAP strum_maps[num_strummap_tracks]; + + // Begin markup section + if (format >= 0x7) + ImprovSoloCueInfo cueInfo1; + if (format >= 0x8) + VocalImprovChordInfo voxChordInfo; + if (format >= 0xA) + RBLoopDefnVector loopDefns; + if (format >= 0xC) + ImprovSoloCueInfo cueInfo2; + + if(format == 0x2f) { // RBVR Specific section + RBVREVENTS vr_events; + } + MidiFileResource midiFileResource; + // File End +} +else if(ReadInt() == 0x2){ // mid_ps4/pc + MidiFileResource midiFileResource; } \ No newline at end of file diff --git a/010/ForgeTex.bt b/010/ForgeTex.bt index cada289..e27d28a 100644 --- a/010/ForgeTex.bt +++ b/010/ForgeTex.bt @@ -1,70 +1,70 @@ -// HMX Forge Texture format (.png_platform, .bmp_platform) -LittleEndian(); -typedef struct { - int Width; - int Height; - int Flag; - if(Version == 0xC) { - int unk[2]; - } -} MipmapInfo; -typedef struct { - int Size; - byte Data[Size]; -} MipmapData; - -int Magic; -int Version; -Assert(Magic == 6 || Magic == 4, "Magic number == 6 or 4"); -if (Magic == 6 && Version != 0xC) { - int Unknown; - int Unknown; - int UnknownSixteen; - int Unknown; - int Unknown; - int UnknownFlag; - int Unknown; - int UnknownFour; - int Unknown; - int UnknownThirtyTwo; - int Unk[12]; - int UnknownSix; - int UnknownSixteen2; - int Unknown; - // these MIGHT be related to texture compression - // 1 = DXT1 ?? - // 3 = DXT5 ?? - int UnknownCompressionFormat; - int UnknownCompressionFormat; - int Unknown; - int Negative; - int Negative; - int BitsPerPixel; // Seen: 4 and 8 - int UnknownTwo; - int UnknownOne; - int UnknownTwo; - int UnknownTwo; - int Unknown; - int UnknownTwo; - int UnknownThree; - int Unk2[5]; -} -else if (Magic == 6 && Version == 0xC) { - FSeek(0x84); -} -else { - FSeek(0xAC); -} - -int MipmapLevels; -MipmapInfo info[MipmapLevels]; -int Unknown6; -// Image Data for each mipmap level -MipmapData ImageData[MipmapLevels]; -int Unknown; -int Unknown; -float Unknown; -float Unknown; -float Unknown; -float Unknown; +// HMX Forge Texture format (.png_platform, .bmp_platform) +LittleEndian(); +typedef struct { + int Width; + int Height; + int Flag; + if(Version == 0xC) { + int unk[2]; + } +} MipmapInfo; +typedef struct { + int Size; + byte Data[Size]; +} MipmapData; + +int Magic; +int Version; +Assert(Magic == 6 || Magic == 4, "Magic number == 6 or 4"); +if (Magic == 6 && Version != 0xC) { + int Unknown; + int Unknown; + int UnknownSixteen; + int Unknown; + int Unknown; + int UnknownFlag; + int Unknown; + int UnknownFour; + int Unknown; + int UnknownThirtyTwo; + int Unk[12]; + int UnknownSix; + int UnknownSixteen2; + int Unknown; + // these MIGHT be related to texture compression + // 1 = DXT1 ?? + // 3 = DXT5 ?? + int UnknownCompressionFormat; + int UnknownCompressionFormat; + int Unknown; + int Negative; + int Negative; + int BitsPerPixel; // Seen: 4 and 8 + int UnknownTwo; + int UnknownOne; + int UnknownTwo; + int UnknownTwo; + int Unknown; + int UnknownTwo; + int UnknownThree; + int Unk2[5]; +} +else if (Magic == 6 && Version == 0xC) { + FSeek(0x84); +} +else { + FSeek(0xAC); +} + +int MipmapLevels; +MipmapInfo info[MipmapLevels]; +int Unknown6; +// Image Data for each mipmap level +MipmapData ImageData[MipmapLevels]; +int Unknown; +int Unknown; +float Unknown; +float Unknown; +float Unknown; +float Unknown; int Unknown; \ No newline at end of file diff --git a/010/common.bt b/010/common.bt index 65a6031..017cc13 100644 --- a/010/common.bt +++ b/010/common.bt @@ -1,11 +1,11 @@ -// Common definitions for Forge stuff - -// pascal string (32-bit length prefixed ASCII) -typedef struct { - uint strlen; - char name[strlen]; +// Common definitions for Forge stuff + +// pascal string (32-bit length prefixed ASCII) +typedef struct { + uint strlen; + char name[strlen]; } PSTR; -string PSTR_READ(PSTR&st){ +string PSTR_READ(PSTR&st){ if(st.strlen == 0) return ""; return st.name; } \ No newline at end of file diff --git a/010/lipsync.bt b/010/lipsync.bt index e0e1374..02c0138 100644 --- a/010/lipsync.bt +++ b/010/lipsync.bt @@ -1,86 +1,86 @@ -#include "common.bt" -LittleEndian(); - -int version; -int subtype; -float frameRate; -struct { - int num_strings; - PSTR strings[num_strings]; -} visemes; -struct { - int num_strings; - PSTR strings[num_strings]; -} instruments; -int count_off; -int offset_data[count_off]; // Offsets for following data - -typedef struct { - ubyte visemeIndex; - - if (visemeIndex != 0xFF) - ubyte weight; -} visemeChange; - -string VC_READ(visemeChange &vc){ - if (vc.visemeIndex == 0xFF) - return "0xFF"; +#include "common.bt" +LittleEndian(); + +int version; +int subtype; +float frameRate; +struct { + int num_strings; + PSTR strings[num_strings]; +} visemes; +struct { + int num_strings; + PSTR strings[num_strings]; +} instruments; +int count_off; +int offset_data[count_off]; // Offsets for following data + +typedef struct { + ubyte visemeIndex; + + if (visemeIndex != 0xFF) + ubyte weight; +} visemeChange; + +string VC_READ(visemeChange &vc){ + if (vc.visemeIndex == 0xFF) + return "0xFF"; return visemes.strings[vc.visemeIndex].name; -} - -int getSize(int off, int max) { - if (max <= 0) return 0; - - // Reads in size until terminating character - local int i; - for (i = 0; i < max; i += 2) { - if (ReadUByte(off + i) == 0xFF) return i + 1; - } - - return max; -} - -// Calculates lengths for interlaced lipsync data -local int i, size, keySize; -for (i = 0; i < count_off - 1; i++) { - size = offset_data[i+1]-offset_data[i]; - if (size == 0) continue; - - struct { - keySize = getSize(FTell(), size); - - // Part 1 - if (keySize > 0) { - struct { - visemeChange changes[(keySize >> 1) + (keySize % 2)]; - } lipsync1; - } - size -= keySize; - keySize = getSize(FTell(), size); - - // Part 2 - if (keySize > 0) { - struct { - visemeChange changes[(keySize >> 1) + (keySize % 2)]; - } lipsync2; - } - size -= keySize; - keySize = getSize(FTell(), size); - - // Part 3 - if (keySize > 0) { - struct { - visemeChange changes[(keySize >> 1) + (keySize % 2)]; - } lipsync3; - } - size -= keySize; - keySize = getSize(FTell(), size); - - // Part 4 - Not observed yet - if (keySize > 0) { - struct { - visemeChange changes[(keySize >> 1) + (keySize % 2)]; - } lipsync4; - } - } key_frame_data; +} + +int getSize(int off, int max) { + if (max <= 0) return 0; + + // Reads in size until terminating character + local int i; + for (i = 0; i < max; i += 2) { + if (ReadUByte(off + i) == 0xFF) return i + 1; + } + + return max; +} + +// Calculates lengths for interlaced lipsync data +local int i, size, keySize; +for (i = 0; i < count_off - 1; i++) { + size = offset_data[i+1]-offset_data[i]; + if (size == 0) continue; + + struct { + keySize = getSize(FTell(), size); + + // Part 1 + if (keySize > 0) { + struct { + visemeChange changes[(keySize >> 1) + (keySize % 2)]; + } lipsync1; + } + size -= keySize; + keySize = getSize(FTell(), size); + + // Part 2 + if (keySize > 0) { + struct { + visemeChange changes[(keySize >> 1) + (keySize % 2)]; + } lipsync2; + } + size -= keySize; + keySize = getSize(FTell(), size); + + // Part 3 + if (keySize > 0) { + struct { + visemeChange changes[(keySize >> 1) + (keySize % 2)]; + } lipsync3; + } + size -= keySize; + keySize = getSize(FTell(), size); + + // Part 4 - Not observed yet + if (keySize > 0) { + struct { + visemeChange changes[(keySize >> 1) + (keySize % 2)]; + } lipsync4; + } + } key_frame_data; } \ No newline at end of file diff --git a/010/rbsong.bt b/010/rbsong.bt index 419bd78..79a9d63 100644 --- a/010/rbsong.bt +++ b/010/rbsong.bt @@ -1,269 +1,269 @@ -#include "common.bt" - -// This file seems to contain a tree of Forge game objects -// The objects are saved with their structure (property names/types) and state (prop values) -// Many of the forge file formats have these serialized objects in them. -// Some object definitions are present in the .script_dta_ps4 files, -// while others are hardcoded into the game (such as EntityHeader, RBSongMetadata, etc) - -typedef struct { - enum { - kFloat = 0x0, - // 0x1, 0x2 - kInt = 0x3, - kByte = 0x5, - kFlag = 0x7, - kEnum = 0x8, - kBool = 0x9, - kSymbol = 0xB, - kString = 0xC, - // 0xD, 0xE - kStruct = 0xF, - kDrivenProp = 0x10 - } data_type : 8; - int is_array : 1; -} prop_type; -string prop_type_read(prop_type& t) -{ - local string result; - SPrintf(result, "%s%s", EnumToString(t.data_type), t.is_array ? "[]" : ""); - return result; -} - -typedef struct { - int flag_0 : 1; - int ChangeName : 1; - int ChangeLayer : 1; - int Delete : 1; - int ChangeProps : 1; - int AddComponent : 1; - int RemComponent : 1; - int ShowInLister : 1; - int Selectable : 1; -} editor_capability_flags; - -// Arrays might be 0x100 | type ? - -struct PropDef { - PSTR name; - prop_type type; - if(type.is_array){ - int array_type; - } - if(type.data_type == kStruct){ - int64 refcount; - int num_children; - struct PropDef children[num_children]; - } -}; -string prop_read(struct PropDef& p) { - local string name; - SPrintf(name, "%s:%s", p.name.name, prop_type_read(p.type)); - return name; -} - -typedef struct propVal (struct PropDef& p) { - local string name; - SPrintf(name, "%s:%s", p.name.name, prop_type_read(p.type)); - if(p.type.is_array){ - int num_elements; - if(num_elements != 0){ - switch(p.type.data_type){ - case kFloat: - float floatVals[num_elements]; - break; - case kInt: - int intVals[num_elements]; - break; - case kFlag: - int flagVals[num_elements]; - break; - case kEnum: - int64 enumVals[num_elements]; - break; - case kBool: - case kByte: - byte boolVals[num_elements]; - break; - case kSymbol: - struct { - PSTR symbolVal; - if((symbolVal.strlen == 0) && (ReadByte() == 0) && (ReadShort() != 0)) - FSkip(1); - } symbolVals[num_elements] ; - break; - case kString: - struct { - PSTR stringVal; - if(ReadByte() == 0) FSkip(1); - } stringVals[num_elements] ; - break; - case kStruct: - struct (struct PropDef& p) { - local int x = 0; - for(x = 0; x < p.num_children; x++){ - struct propVal child(p.children[x]) ; - } - } structVals(p)[num_elements]; - break; - case kDrivenProp: - struct { - int64 unk_driven_prop_1; - PSTR propType; - int32 unk_driven_prop_2; - int64 unk_driven_prop_3; - PSTR propName; - } drivenProps[num_elements] ; - break; - default: - int unkVal[num_elements]; - break; - } - } - } else { - switch(p.type.data_type){ - case kFloat: - float floatVal; - break; - case kInt: - int intVal; - break; - case kFlag: - int flagVal; - break; - case kEnum: - int64 enumVal; - break; - case kBool: - case kByte: - byte boolVal; - break; - case kSymbol: - PSTR symbolVal; - // Weird: sometimes there is an extra '\0' after symbols / strings? - if((symbolVal.strlen == 0) && (ReadByte() == 0) && (ReadShort() != 0)) - FSkip(1); - else if(ReadByte() == 0 && ReadShort() != 0 && (ReadShort() == ReadInt())) - FSkip(1); - break; - case kString: - PSTR stringVal; - if(ReadByte() == 0) - FSkip(1); - break; - case kStruct: - local int x = 0; - for(x = 0; x < p.num_children; x++){ - struct propVal child(p.children[x]) ; - } - break; - case kDrivenProp: - int32 unk_driven_prop_1; - int32 unk_driven_prop_2; - if(unk_driven_prop_2 == 0){ - PSTR propType; - int32 unk_driven_prop_2; - int64 unk_driven_prop_3; - PSTR propName; - } else { - int32 unk1, unk2, unk3; - } - break; - default: - int unkVal; - break; - } - } -} PropVal; -string PropVal_READ(PropVal& v) -{ - return v.name; -} -string propVal_READ(struct propVal& v) -{ - return v.name; -} - -typedef struct { - PSTR ent_name; - PSTR ent_name_2; - int unk_type; - int64 unk_count; - int num_props; - struct PropDef props[num_props]; - local int x = 0; - local int data_size; - for(x = 0; x < num_props; x++){ - PropVal value(props[x]) ; - } - if(data_size != 0) - char prop_data[data_size]; -} Component; -string COM_READ(Component& e){ - return e.ent_name.name; -} - -typedef struct entity { - int16 index_0; - int16 index_1; - //Assert(index_0 == index_1, "indices should be equal"); - if(index_0 == -1 && index_1 == -1) { - } - else { - int32 unk_two_0; - //Assert(unk_two_0 == 2, "unk_two_0 should be 2"); - PSTR name; - int32 num_children; - Component coms[num_children] ; - } -} forge_Entity; -string forge_object_read(forge_Entity& f){ - return f.index_0 == -1 ? "TODO" : f.name.name; -} - -typedef struct { - int32 version; - int32 more_data; -} forge_hdr; - -typedef struct forge_tree(forge_hdr& hdr){ - if(ReadInt() == 0){ - FSkip(4); - if(hdr.version > 0xF) { - int32 unk; - } - if(hdr.version > 0xE) { - int32 unk5; - } - int32 unk_19_or_20; - int32 unk_one_1; - int32 same_19_or_20; - if(hdr.version > 0xE) { - int32 unk5; - } - int32 unk_zero_1; - int16 unk_flag1; - int32 num_objects; - if(hdr.version == 0x10) { - forge_Entity entities[num_objects/4]; - int32 unknown_tail_data[9]; - } - else { - forge_Entity entities[num_objects]; - } - } else { - PSTR type; - PSTR value; - } -} forge_tree; - -// The file is a list of what I am calling forge_tree structs. -// They start with a header. At the end of the list there is another header -// that signals the end of the file by setting more_data=0 -forge_hdr hdr; -local int cont = hdr.more_data; -while(cont) { - forge_tree tree(hdr); - forge_hdr hdr; - cont = hdr.more_data; -} +#include "common.bt" + +// This file seems to contain a tree of Forge game objects +// The objects are saved with their structure (property names/types) and state (prop values) +// Many of the forge file formats have these serialized objects in them. +// Some object definitions are present in the .script_dta_ps4 files, +// while others are hardcoded into the game (such as EntityHeader, RBSongMetadata, etc) + +typedef struct { + enum { + kFloat = 0x0, + // 0x1, 0x2 + kInt = 0x3, + kByte = 0x5, + kFlag = 0x7, + kEnum = 0x8, + kBool = 0x9, + kSymbol = 0xB, + kString = 0xC, + // 0xD, 0xE + kStruct = 0xF, + kDrivenProp = 0x10 + } data_type : 8; + int is_array : 1; +} prop_type; +string prop_type_read(prop_type& t) +{ + local string result; + SPrintf(result, "%s%s", EnumToString(t.data_type), t.is_array ? "[]" : ""); + return result; +} + +typedef struct { + int flag_0 : 1; + int ChangeName : 1; + int ChangeLayer : 1; + int Delete : 1; + int ChangeProps : 1; + int AddComponent : 1; + int RemComponent : 1; + int ShowInLister : 1; + int Selectable : 1; +} editor_capability_flags; + +// Arrays might be 0x100 | type ? + +struct PropDef { + PSTR name; + prop_type type; + if(type.is_array){ + int array_type; + } + if(type.data_type == kStruct){ + int64 refcount; + int num_children; + struct PropDef children[num_children]; + } +}; +string prop_read(struct PropDef& p) { + local string name; + SPrintf(name, "%s:%s", p.name.name, prop_type_read(p.type)); + return name; +} + +typedef struct propVal (struct PropDef& p) { + local string name; + SPrintf(name, "%s:%s", p.name.name, prop_type_read(p.type)); + if(p.type.is_array){ + int num_elements; + if(num_elements != 0){ + switch(p.type.data_type){ + case kFloat: + float floatVals[num_elements]; + break; + case kInt: + int intVals[num_elements]; + break; + case kFlag: + int flagVals[num_elements]; + break; + case kEnum: + int64 enumVals[num_elements]; + break; + case kBool: + case kByte: + byte boolVals[num_elements]; + break; + case kSymbol: + struct { + PSTR symbolVal; + if((symbolVal.strlen == 0) && (ReadByte() == 0) && (ReadShort() != 0)) + FSkip(1); + } symbolVals[num_elements] ; + break; + case kString: + struct { + PSTR stringVal; + if(ReadByte() == 0) FSkip(1); + } stringVals[num_elements] ; + break; + case kStruct: + struct (struct PropDef& p) { + local int x = 0; + for(x = 0; x < p.num_children; x++){ + struct propVal child(p.children[x]) ; + } + } structVals(p)[num_elements]; + break; + case kDrivenProp: + struct { + int64 unk_driven_prop_1; + PSTR propType; + int32 unk_driven_prop_2; + int64 unk_driven_prop_3; + PSTR propName; + } drivenProps[num_elements] ; + break; + default: + int unkVal[num_elements]; + break; + } + } + } else { + switch(p.type.data_type){ + case kFloat: + float floatVal; + break; + case kInt: + int intVal; + break; + case kFlag: + int flagVal; + break; + case kEnum: + int64 enumVal; + break; + case kBool: + case kByte: + byte boolVal; + break; + case kSymbol: + PSTR symbolVal; + // Weird: sometimes there is an extra '\0' after symbols / strings? + if((symbolVal.strlen == 0) && (ReadByte() == 0) && (ReadShort() != 0)) + FSkip(1); + else if(ReadByte() == 0 && ReadShort() != 0 && (ReadShort() == ReadInt())) + FSkip(1); + break; + case kString: + PSTR stringVal; + if(ReadByte() == 0) + FSkip(1); + break; + case kStruct: + local int x = 0; + for(x = 0; x < p.num_children; x++){ + struct propVal child(p.children[x]) ; + } + break; + case kDrivenProp: + int32 unk_driven_prop_1; + int32 unk_driven_prop_2; + if(unk_driven_prop_2 == 0){ + PSTR propType; + int32 unk_driven_prop_2; + int64 unk_driven_prop_3; + PSTR propName; + } else { + int32 unk1, unk2, unk3; + } + break; + default: + int unkVal; + break; + } + } +} PropVal; +string PropVal_READ(PropVal& v) +{ + return v.name; +} +string propVal_READ(struct propVal& v) +{ + return v.name; +} + +typedef struct { + PSTR ent_name; + PSTR ent_name_2; + int unk_type; + int64 unk_count; + int num_props; + struct PropDef props[num_props]; + local int x = 0; + local int data_size; + for(x = 0; x < num_props; x++){ + PropVal value(props[x]) ; + } + if(data_size != 0) + char prop_data[data_size]; +} Component; +string COM_READ(Component& e){ + return e.ent_name.name; +} + +typedef struct entity { + int16 index_0; + int16 index_1; + //Assert(index_0 == index_1, "indices should be equal"); + if(index_0 == -1 && index_1 == -1) { + } + else { + int32 unk_two_0; + //Assert(unk_two_0 == 2, "unk_two_0 should be 2"); + PSTR name; + int32 num_children; + Component coms[num_children] ; + } +} forge_Entity; +string forge_object_read(forge_Entity& f){ + return f.index_0 == -1 ? "TODO" : f.name.name; +} + +typedef struct { + int32 version; + int32 more_data; +} forge_hdr; + +typedef struct forge_tree(forge_hdr& hdr){ + if(ReadInt() == 0){ + FSkip(4); + if(hdr.version > 0xF) { + int32 unk; + } + if(hdr.version > 0xE) { + int32 unk5; + } + int32 unk_19_or_20; + int32 unk_one_1; + int32 same_19_or_20; + if(hdr.version > 0xE) { + int32 unk5; + } + int32 unk_zero_1; + int16 unk_flag1; + int32 num_objects; + if(hdr.version == 0x10) { + forge_Entity entities[num_objects/4]; + int32 unknown_tail_data[9]; + } + else { + forge_Entity entities[num_objects]; + } + } else { + PSTR type; + PSTR value; + } +} forge_tree; + +// The file is a list of what I am calling forge_tree structs. +// They start with a header. At the end of the list there is another header +// that signals the end of the file by setting more_data=0 +forge_hdr hdr; +local int cont = hdr.more_data; +while(cont) { + forge_tree tree(hdr); + forge_hdr hdr; + cont = hdr.more_data; +} diff --git a/010/songdta.bt b/010/songdta.bt index 950f9c6..d86b3e0 100644 --- a/010/songdta.bt +++ b/010/songdta.bt @@ -1,47 +1,47 @@ -// Forge .songdta file - -LittleEndian(); - -uint songdta_type; -uint song_id; -short version; -char game_origin[18]; -float preview_start; -float preview_end; -char name[256]; -char artist[256]; -char album_name[256]; -short album_track_number; -FSeek(FTell()+2); -int album_year; -int original_year; -char genre[64]; -float song_length; -float guitar; -float bass; -float vocals; -float drum; -float band; -float keys; -float real_keys; -byte tutorial; -byte album_art; -byte cover; -enum { - Male = 1, - Female = 2 -} vocal_gender; -char anim_tempo[16]; -char has_markup; -FSeek(FTell()+3); -int vocal_parts; // not certain about this one -struct { - int unk_0 : 1; - int vocals : 1; - int unk_2 : 1; - int unk_3 : 1; - int unk_4 : 1; - int unk_5 : 1; -} solos; -char fake; +// Forge .songdta file + +LittleEndian(); + +uint songdta_type; +uint song_id; +short version; +char game_origin[18]; +float preview_start; +float preview_end; +char name[256]; +char artist[256]; +char album_name[256]; +short album_track_number; +FSeek(FTell()+2); +int album_year; +int original_year; +char genre[64]; +float song_length; +float guitar; +float bass; +float vocals; +float drum; +float band; +float keys; +float real_keys; +byte tutorial; +byte album_art; +byte cover; +enum { + Male = 1, + Female = 2 +} vocal_gender; +char anim_tempo[16]; +char has_markup; +FSeek(FTell()+3); +int vocal_parts; // not certain about this one +struct { + int unk_0 : 1; + int vocals : 1; + int unk_2 : 1; + int unk_3 : 1; + int unk_4 : 1; + int unk_5 : 1; +} solos; +char fake; char shortname[256]; \ No newline at end of file diff --git a/AnalysisReport.sarif b/AnalysisReport.sarif new file mode 100644 index 0000000..46656b6 --- /dev/null +++ b/AnalysisReport.sarif @@ -0,0 +1,239 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Dependency Analysis", + "semanticVersion": "0.4.336902", + "informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview", + "rules": [ + { + "id": "UA106", + "name": "PackageToBeAdded", + "fullDescription": { + "text": "Packages that need to be added in order to upgrade the project to chosen TFM" + }, + "helpUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview" + }, + { + "id": "UA105", + "name": "PackageToBeDeleted", + "fullDescription": { + "text": "Packages that need to be deleted in order to upgrade the project to chosen TFM" + }, + "helpUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview" + } + ] + } + }, + "results": [ + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/LibForge/LibForge.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeTool/ForgeTool.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA105", + "message": { + "text": "Package OpenTK, Version=3.0.1 does not support the target(s) net6.0-windows but a newer version (3.3.2) does. Package OpenTK needs to be upgraded from 3.0.1 to 3.3.2." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA105", + "message": { + "text": "Package OpenTK.GLControl, Version=3.0.1 needs to be deleted." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA105", + "message": { + "text": "Package OpenTK, Version=3.0.1 needs to be deleted." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package OpenTK, Version=3.3.2 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package OpenTK.GLControl, Version=3.1.0 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.Windows.Compatibility, Version=6.0.0 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/ForgeToolGUI/ForgeToolGUI.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/LibForge/LibForgeTests/LibForgeTests.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/Dependencies/GameArchives/Library/GameArchives.csproj" + }, + "region": {} + } + } + ] + }, + { + "ruleId": "UA106", + "message": { + "text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.336902 needs to be added." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/Users/Windows%20Games/Documents/LibForge-Amp2016/Dependencies/LibOrbisPkg/LibOrbisPkg/LibOrbisPkg.csproj" + }, + "region": {} + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + }, + { + "tool": { + "driver": { + "name": "API Upgradability", + "semanticVersion": "0.4.336902", + "informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview" + } + }, + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/Dependencies/GameArchives b/Dependencies/GameArchives deleted file mode 160000 index 8d718b4..0000000 --- a/Dependencies/GameArchives +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8d718b41e2f672bb69da58d20a0766874a8a65ba diff --git a/Dependencies/GameArchives/.gitattributes b/Dependencies/GameArchives/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/Dependencies/GameArchives/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Dependencies/GameArchives/.gitignore b/Dependencies/GameArchives/.gitignore new file mode 100644 index 0000000..b06e864 --- /dev/null +++ b/Dependencies/GameArchives/.gitignore @@ -0,0 +1,212 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml diff --git a/Dependencies/GameArchives/ArchiveExplorer/App.config b/Dependencies/GameArchives/ArchiveExplorer/App.config new file mode 100644 index 0000000..d1428ad --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.Designer.cs b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.Designer.cs new file mode 100644 index 0000000..02846cd --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.Designer.cs @@ -0,0 +1,220 @@ +namespace ArchiveExplorer +{ + partial class ArchiveExplorer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.detailsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.iconsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.listToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openGitHubRepositoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.packagesTabControl = new System.Windows.Forms.TabControl(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.spinnerLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.menuStrip1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.viewToolStripMenuItem, + this.helpToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(684, 24); + this.menuStrip1.TabIndex = 0; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openToolStripMenuItem, + this.closeToolStripMenuItem, + this.exitToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // openToolStripMenuItem + // + this.openToolStripMenuItem.Name = "openToolStripMenuItem"; + this.openToolStripMenuItem.Size = new System.Drawing.Size(112, 22); + this.openToolStripMenuItem.Text = "Open..."; + this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); + // + // closeToolStripMenuItem + // + this.closeToolStripMenuItem.Name = "closeToolStripMenuItem"; + this.closeToolStripMenuItem.Size = new System.Drawing.Size(112, 22); + this.closeToolStripMenuItem.Text = "Close"; + this.closeToolStripMenuItem.Click += new System.EventHandler(this.closeToolStripMenuItem_Click); + // + // exitToolStripMenuItem + // + this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; + this.exitToolStripMenuItem.Size = new System.Drawing.Size(112, 22); + this.exitToolStripMenuItem.Text = "Exit"; + this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); + // + // viewToolStripMenuItem + // + this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.detailsToolStripMenuItem, + this.iconsToolStripMenuItem, + this.listToolStripMenuItem}); + this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; + this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.viewToolStripMenuItem.Text = "View"; + // + // detailsToolStripMenuItem + // + this.detailsToolStripMenuItem.Checked = true; + this.detailsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.detailsToolStripMenuItem.Name = "detailsToolStripMenuItem"; + this.detailsToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.detailsToolStripMenuItem.Text = "Details"; + this.detailsToolStripMenuItem.Click += new System.EventHandler(this.detailsToolStripMenuItem_Click); + // + // iconsToolStripMenuItem + // + this.iconsToolStripMenuItem.Name = "iconsToolStripMenuItem"; + this.iconsToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.iconsToolStripMenuItem.Text = "Icons"; + this.iconsToolStripMenuItem.Click += new System.EventHandler(this.iconsToolStripMenuItem_Click); + // + // listToolStripMenuItem + // + this.listToolStripMenuItem.Name = "listToolStripMenuItem"; + this.listToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.listToolStripMenuItem.Text = "List"; + this.listToolStripMenuItem.Click += new System.EventHandler(this.listToolStripMenuItem_Click); + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openGitHubRepositoryToolStripMenuItem}); + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Text = "Help"; + // + // openGitHubRepositoryToolStripMenuItem + // + this.openGitHubRepositoryToolStripMenuItem.Name = "openGitHubRepositoryToolStripMenuItem"; + this.openGitHubRepositoryToolStripMenuItem.Size = new System.Drawing.Size(200, 22); + this.openGitHubRepositoryToolStripMenuItem.Text = "Open GitHub repository"; + this.openGitHubRepositoryToolStripMenuItem.Click += new System.EventHandler(this.gitHubToolStripMenuItem_Click); + // + // packagesTabControl + // + this.packagesTabControl.AllowDrop = true; + this.packagesTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.packagesTabControl.Location = new System.Drawing.Point(0, 27); + this.packagesTabControl.Multiline = true; + this.packagesTabControl.Name = "packagesTabControl"; + this.packagesTabControl.SelectedIndex = 0; + this.packagesTabControl.Size = new System.Drawing.Size(684, 409); + this.packagesTabControl.TabIndex = 1; + this.packagesTabControl.DragDrop += new System.Windows.Forms.DragEventHandler(this.packagesTabControl_DragDrop); + this.packagesTabControl.DragEnter += new System.Windows.Forms.DragEventHandler(this.packagesTabControl_DragEnter); + this.packagesTabControl.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tabControl1_Click); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.spinnerLabel, + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 439); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(684, 22); + this.statusStrip1.TabIndex = 2; + this.statusStrip1.Text = "statusStrip1"; + // + // spinnerLabel + // + this.spinnerLabel.Image = global::ArchiveExplorer.Properties.Resources.spinner; + this.spinnerLabel.Name = "spinnerLabel"; + this.spinnerLabel.Size = new System.Drawing.Size(16, 17); + this.spinnerLabel.Visible = false; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(42, 17); + this.toolStripStatusLabel1.Text = "Ready."; + // + // ArchiveExplorer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(684, 461); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.packagesTabControl); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.Name = "ArchiveExplorer"; + this.Text = "ArchiveExplorer"; + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem closeToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem viewToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem detailsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem iconsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem listToolStripMenuItem; + private System.Windows.Forms.TabControl packagesTabControl; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.ToolStripStatusLabel spinnerLabel; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openGitHubRepositoryToolStripMenuItem; + } +} + diff --git a/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.cs b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.cs new file mode 100644 index 0000000..7fdcae3 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.cs @@ -0,0 +1,202 @@ +/* + * ArchiveExplorer.cs + * + * Copyright (c) 2015,2016, maxton. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + */ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using GameArchives; +using System.IO; +using FolderSelect; +using LibArchiveExplorer; + +namespace ArchiveExplorer +{ + public partial class ArchiveExplorer : Form + { + private PackageManager pm; + + public ArchiveExplorer() + { + InitializeComponent(); + pm = PackageManager.GetInstance(); + pm.Spinner = this.spinnerLabel; + pm.StatusLabel = this.toolStripStatusLabel1; + pm.Loader = LoadFile; + pm.SetReady(); + string[] args = Environment.GetCommandLineArgs(); + if (args.Length > 1) + { + if(File.Exists(args[1])) + { + LoadFile(Util.LocalFile(args[1])); + } + } + } + + private string passcode_popup(string prompt) + { + var form = new KeyRequestForm(prompt); + return form.ShowDialog() == DialogResult.OK ? form.Passcode : ""; + } + + /// + /// Deal with a new file. + /// + /// + private async Task LoadFile(IFile file) + { + var newPage = new TabPage(); + newPage.Text = "Loading..."; + packagesTabControl.Controls.Add(newPage); + PackageView packageView = null; + try + { + var newPackage = await Task.Run(() => PackageReader.ReadPackageFromFile(file, passcode_popup)); + packageView = new PackageView(newPackage, pm); + packageView.OnRemoveTab += RemoveTab; + newPage.Text = newPackage.FileName; + newPage.Controls.Add(packageView); + packageView.Tag = newPage; + packageView.SetView(view); + packageView.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + packageView.Dock = System.Windows.Forms.DockStyle.Fill; + packageView.Location = new System.Drawing.Point(3, 3); + packageView.Margin = new System.Windows.Forms.Padding(0); + packageView.Name = "packageView"; + packageView.TabIndex = 0; + packagesTabControl.SelectedTab = newPage; + } + catch (Exception ex) + { + packagesTabControl.Controls.Remove(newPage); + MessageBox.Show("Could not load archive!" + Environment.NewLine + ex.Message, "Error"); + } + return packageView; + }//LoadFile + + public void RemoveTab(TabPage p) + { + packagesTabControl.Controls.Remove(p); + } + + + + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + var of = new OpenFileDialog(); + of.Title = "Select package to open."; + of.Filter += "All Files (*.*)|*.*|" + PackageReader.SupportedFormats; + if (of.ShowDialog() == DialogResult.OK) + { + LoadFile(Util.LocalFile(of.FileName)); + } + } + + private void detailsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!detailsToolStripMenuItem.Checked) + { + detailsToolStripMenuItem.Checked = true; + iconsToolStripMenuItem.Checked = false; + listToolStripMenuItem.Checked = false; + SetView(View.Details); + } + } + + private void iconsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!iconsToolStripMenuItem.Checked) + { + detailsToolStripMenuItem.Checked = false; + iconsToolStripMenuItem.Checked = true; + listToolStripMenuItem.Checked = false; + SetView(View.LargeIcon); + } + } + + private void listToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!listToolStripMenuItem.Checked) + { + detailsToolStripMenuItem.Checked = false; + iconsToolStripMenuItem.Checked = false; + listToolStripMenuItem.Checked = true; + SetView(View.List); + } + } + + private View view = View.Details; + private void SetView(View v) + { + view = v; + foreach(TabPage t in packagesTabControl.TabPages) + { + if(t.Controls.Count > 0) + (t.Controls[0] as PackageView)?.SetView(v); + } + } + + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + Application.Exit(); + } + + private void closeToolStripMenuItem_Click(object sender, EventArgs e) + { + (packagesTabControl.SelectedTab?.Controls[0] as PackageView)?.Unload(); + } + + private void tabControl1_Click(object sender, MouseEventArgs e) + { + var ctrl = sender as TabControl; + if (e.Button == MouseButtons.Middle) + { + (ctrl.TabPages.Cast() + .Where((t, i) => ctrl.GetTabRect(i).Contains(e.Location)) + .First().Controls[0] as PackageView).Unload(); + } + } + + private void gitHubToolStripMenuItem_Click(object sender, EventArgs e) + { + System.Diagnostics.Process.Start("https://github.com/maxton/GameArchives"); + } + + private void packagesTabControl_DragDrop(object sender, DragEventArgs e) + { + var files = e.Data.GetData(DataFormats.FileDrop) as string[]; + foreach(string file in files) + { + LoadFile(Util.LocalFile(file)); + } + } + + private void packagesTabControl_DragEnter(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + e.Effect = DragDropEffects.Copy; + } + } +} diff --git a/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.csproj b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.csproj new file mode 100644 index 0000000..d591f90 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.csproj @@ -0,0 +1,28 @@ + + + net6.0 + WinExe + false + true + true + + + + + + + + + + + + + + + + + all + + + + \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.licenseheader b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.licenseheader new file mode 100644 index 0000000..058d400 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.licenseheader @@ -0,0 +1,21 @@ +extensions: designer.cs generated.cs +extensions: .cs .cpp .h +/* + * %FileName% + * + * Copyright (c) 2015,%CurrentYear%, maxton. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + */ \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.resx b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.resx new file mode 100644 index 0000000..f1d13d7 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/ArchiveExplorer.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/Images/File_large.png b/Dependencies/GameArchives/ArchiveExplorer/Images/File_large.png new file mode 100644 index 0000000..4618684 Binary files /dev/null and b/Dependencies/GameArchives/ArchiveExplorer/Images/File_large.png differ diff --git a/Dependencies/GameArchives/ArchiveExplorer/Images/File_small.png b/Dependencies/GameArchives/ArchiveExplorer/Images/File_small.png new file mode 100644 index 0000000..74821cb Binary files /dev/null and b/Dependencies/GameArchives/ArchiveExplorer/Images/File_small.png differ diff --git a/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_large.png b/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_large.png new file mode 100644 index 0000000..5eee512 Binary files /dev/null and b/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_large.png differ diff --git a/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_small.png b/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_small.png new file mode 100644 index 0000000..bbcff1e Binary files /dev/null and b/Dependencies/GameArchives/ArchiveExplorer/Images/Folder_small.png differ diff --git a/Dependencies/GameArchives/ArchiveExplorer/Images/spinner.gif b/Dependencies/GameArchives/ArchiveExplorer/Images/spinner.gif new file mode 100644 index 0000000..ad63607 Binary files /dev/null and b/Dependencies/GameArchives/ArchiveExplorer/Images/spinner.gif differ diff --git a/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.Designer.cs b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.Designer.cs new file mode 100644 index 0000000..13e091a --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.Designer.cs @@ -0,0 +1,99 @@ +namespace ArchiveExplorer +{ + partial class KeyRequestForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button1 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.passcodeTextBox = new System.Windows.Forms.TextBox(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // button1 + // + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Location = new System.Drawing.Point(148, 83); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 0; + this.button1.Text = "OK"; + this.button1.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(150, 13); + this.label1.TabIndex = 1; + this.label1.Text = "A passcode or key is needed: "; + // + // passcodeTextBox + // + this.passcodeTextBox.Location = new System.Drawing.Point(15, 26); + this.passcodeTextBox.Name = "passcodeTextBox"; + this.passcodeTextBox.Size = new System.Drawing.Size(344, 20); + this.passcodeTextBox.TabIndex = 2; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Location = new System.Drawing.Point(15, 52); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(107, 17); + this.checkBox1.TabIndex = 3; + this.checkBox1.Text = "Decode from hex"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // KeyRequestForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(371, 118); + this.ControlBox = false; + this.Controls.Add(this.checkBox1); + this.Controls.Add(this.passcodeTextBox); + this.Controls.Add(this.label1); + this.Controls.Add(this.button1); + this.Name = "KeyRequestForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "Decryption Key"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox passcodeTextBox; + private System.Windows.Forms.CheckBox checkBox1; + } +} \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.cs b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.cs new file mode 100644 index 0000000..7f9d594 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ArchiveExplorer +{ + public partial class KeyRequestForm : Form + { + public string Passcode + { + get + { + if (checkBox1.Checked) + { + StringBuilder sb = new StringBuilder(); + var key = passcodeTextBox.Text.Replace(" ", ""); + for (var x = 0; x < key.Length; x += 2) + { + sb.Append((char)Convert.ToByte(key.Substring(x, 2), 16)); + } + return sb.ToString(); + } + return passcodeTextBox.Text; + } + } + public KeyRequestForm(string request = "") + { + InitializeComponent(); + label1.Text += request; + } + } +} diff --git a/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.resx b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/KeyRequestForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/Program.cs b/Dependencies/GameArchives/ArchiveExplorer/Program.cs new file mode 100644 index 0000000..f716994 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Program.cs @@ -0,0 +1,42 @@ +/* + * Program.cs + * + * Copyright (c) 2015,2016, maxton. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ArchiveExplorer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ArchiveExplorer()); + } + } +} diff --git a/Dependencies/GameArchives/ArchiveExplorer/Properties/AssemblyInfo.cs b/Dependencies/GameArchives/ArchiveExplorer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ab628b2 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ArchiveExplorer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ArchiveExplorer")] +[assembly: AssemblyCopyright("Copyright © maxton 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("eac2e703-6d41-4e69-b14d-d881a3c9909c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.12.0.*")] +[assembly: AssemblyFileVersion("0.12.0.0")] diff --git a/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.Designer.cs b/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.Designer.cs new file mode 100644 index 0000000..386068a --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ArchiveExplorer.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ArchiveExplorer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap spinner { + get { + object obj = ResourceManager.GetObject("spinner", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.resx b/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.resx new file mode 100644 index 0000000..a742263 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Images\spinner.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.Designer.cs b/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.Designer.cs new file mode 100644 index 0000000..0ffdf86 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ArchiveExplorer.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.settings b/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Dependencies/GameArchives/ArchiveExplorer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Dependencies/GameArchives/GameArchives.sln b/Dependencies/GameArchives/GameArchives.sln new file mode 100644 index 0000000..f295a8b --- /dev/null +++ b/Dependencies/GameArchives/GameArchives.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2000 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameArchives", "Library\GameArchives.csproj", "{906748F0-3A55-4B20-BCCB-9DC7187F1D5E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiveExplorer", "ArchiveExplorer\ArchiveExplorer.csproj", "{EAC2E703-6D41-4E69-B14D-D881A3C9909C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibArchiveExplorer", "LibArchiveExplorer\LibArchiveExplorer.csproj", "{29722AA8-E9FC-4B5B-9C73-31A6293DBA55}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Release-minimal|Any CPU = Release-minimal|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Release|Any CPU.Build.0 = Release|Any CPU + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Release-minimal|Any CPU.ActiveCfg = Release-minimal|Any CPU + {906748F0-3A55-4B20-BCCB-9DC7187F1D5E}.Release-minimal|Any CPU.Build.0 = Release-minimal|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Release|Any CPU.Build.0 = Release|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Release-minimal|Any CPU.ActiveCfg = Release|Any CPU + {EAC2E703-6D41-4E69-B14D-D881A3C9909C}.Release-minimal|Any CPU.Build.0 = Release|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Release|Any CPU.Build.0 = Release|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Release-minimal|Any CPU.ActiveCfg = Release|Any CPU + {29722AA8-E9FC-4B5B-9C73-31A6293DBA55}.Release-minimal|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DEF13207-4D07-42E5-8F0E-69817D41B933} + EndGlobalSection +EndGlobal diff --git a/Dependencies/GameArchives/GameArchivesTests/GameArchivesTests.csproj b/Dependencies/GameArchives/GameArchivesTests/GameArchivesTests.csproj new file mode 100644 index 0000000..68062b3 --- /dev/null +++ b/Dependencies/GameArchives/GameArchivesTests/GameArchivesTests.csproj @@ -0,0 +1,46 @@ + + + netstandard2.0 + Library + false + + + + + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + all + + + + \ No newline at end of file diff --git a/Dependencies/GameArchives/GameArchivesTests/Local/LocalDirectoryTests.cs b/Dependencies/GameArchives/GameArchivesTests/Local/LocalDirectoryTests.cs new file mode 100644 index 0000000..0969b18 --- /dev/null +++ b/Dependencies/GameArchives/GameArchivesTests/Local/LocalDirectoryTests.cs @@ -0,0 +1,19 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using GameArchives.Local; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GameArchives.Local.Tests +{ + [TestClass()] + public class LocalDirectoryTests + { + [TestMethod()] + public void GetDirectoryTest() + { + } + } +} \ No newline at end of file diff --git a/Dependencies/GameArchives/GameArchivesTests/Properties/AssemblyInfo.cs b/Dependencies/GameArchives/GameArchivesTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7953a35 --- /dev/null +++ b/Dependencies/GameArchives/GameArchivesTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GameArchivesTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GameArchivesTests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4312aa1c-904e-4fcd-860a-aa888d5be0ce")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Dependencies/GameArchives/LICENSE b/Dependencies/GameArchives/LICENSE new file mode 100644 index 0000000..341c30b --- /dev/null +++ b/Dependencies/GameArchives/LICENSE @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.Designer.cs b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.Designer.cs new file mode 100644 index 0000000..c30cc94 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.Designer.cs @@ -0,0 +1,242 @@ +namespace LibArchiveExplorer +{ + partial class EditorWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.discUsageGraphic = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.discUsageBar = new System.Windows.Forms.ProgressBar(); + this.listView1 = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label2 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.lblTotalFileSize = new System.Windows.Forms.Label(); + this.lblTotalFiles = new System.Windows.Forms.Label(); + this.lblPackageSize = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.actionsGroupBox = new System.Windows.Forms.GroupBox(); + this.button1 = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.discUsageGraphic)).BeginInit(); + this.groupBox1.SuspendLayout(); + this.actionsGroupBox.SuspendLayout(); + this.SuspendLayout(); + // + // discUsageGraphic + // + this.discUsageGraphic.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.discUsageGraphic.BackColor = System.Drawing.Color.White; + this.discUsageGraphic.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.discUsageGraphic.Location = new System.Drawing.Point(12, 25); + this.discUsageGraphic.Name = "discUsageGraphic"; + this.discUsageGraphic.Size = new System.Drawing.Size(560, 64); + this.discUsageGraphic.TabIndex = 0; + this.discUsageGraphic.TabStop = false; + this.discUsageGraphic.Paint += new System.Windows.Forms.PaintEventHandler(this.DrawGraphic); + this.discUsageGraphic.MouseDown += new System.Windows.Forms.MouseEventHandler(this.discUsageGraphic_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(65, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Disc Usage:"; + // + // discUsageBar + // + this.discUsageBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.discUsageBar.Enabled = false; + this.discUsageBar.Location = new System.Drawing.Point(12, 95); + this.discUsageBar.Name = "discUsageBar"; + this.discUsageBar.Size = new System.Drawing.Size(560, 23); + this.discUsageBar.Style = System.Windows.Forms.ProgressBarStyle.Continuous; + this.discUsageBar.TabIndex = 2; + // + // listView1 + // + this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1}); + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(12, 124); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(394, 225); + this.listView1.TabIndex = 3; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // columnHeader1 + // + this.columnHeader1.Text = "Name"; + this.columnHeader1.Width = 345; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(17, 30); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(74, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Package size:"; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.lblTotalFileSize); + this.groupBox1.Controls.Add(this.lblTotalFiles); + this.groupBox1.Controls.Add(this.lblPackageSize); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Location = new System.Drawing.Point(413, 249); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(160, 99); + this.groupBox1.TabIndex = 5; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Package Info"; + // + // lblTotalFileSize + // + this.lblTotalFileSize.AutoSize = true; + this.lblTotalFileSize.Location = new System.Drawing.Point(97, 64); + this.lblTotalFileSize.Name = "lblTotalFileSize"; + this.lblTotalFileSize.Size = new System.Drawing.Size(23, 13); + this.lblTotalFileSize.TabIndex = 9; + this.lblTotalFileSize.Text = "0 B"; + // + // lblTotalFiles + // + this.lblTotalFiles.AutoSize = true; + this.lblTotalFiles.Location = new System.Drawing.Point(97, 47); + this.lblTotalFiles.Name = "lblTotalFiles"; + this.lblTotalFiles.Size = new System.Drawing.Size(13, 13); + this.lblTotalFiles.TabIndex = 8; + this.lblTotalFiles.Text = "0"; + // + // lblPackageSize + // + this.lblPackageSize.AutoSize = true; + this.lblPackageSize.Location = new System.Drawing.Point(97, 30); + this.lblPackageSize.Name = "lblPackageSize"; + this.lblPackageSize.Size = new System.Drawing.Size(23, 13); + this.lblPackageSize.TabIndex = 7; + this.lblPackageSize.Text = "0 B"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(20, 64); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(71, 13); + this.label4.TabIndex = 6; + this.label4.Text = "Total file size:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(36, 47); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(55, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Total files:"; + // + // actionsGroupBox + // + this.actionsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.actionsGroupBox.Controls.Add(this.button1); + this.actionsGroupBox.Enabled = false; + this.actionsGroupBox.Location = new System.Drawing.Point(413, 124); + this.actionsGroupBox.Name = "actionsGroupBox"; + this.actionsGroupBox.Size = new System.Drawing.Size(159, 119); + this.actionsGroupBox.TabIndex = 6; + this.actionsGroupBox.TabStop = false; + this.actionsGroupBox.Text = "Actions"; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(6, 19); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(147, 23); + this.button1.TabIndex = 0; + this.button1.Text = "Replace File"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // EditorWindow + // + this.AllowDrop = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(584, 361); + this.Controls.Add(this.actionsGroupBox); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.listView1); + this.Controls.Add(this.discUsageBar); + this.Controls.Add(this.label1); + this.Controls.Add(this.discUsageGraphic); + this.MinimumSize = new System.Drawing.Size(600, 400); + this.Name = "EditorWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Package Editor"; + ((System.ComponentModel.ISupportInitialize)(this.discUsageGraphic)).EndInit(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.actionsGroupBox.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox discUsageGraphic; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ProgressBar discUsageBar; + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label lblTotalFileSize; + private System.Windows.Forms.Label lblTotalFiles; + private System.Windows.Forms.Label lblPackageSize; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.GroupBox actionsGroupBox; + } +} + diff --git a/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.cs b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.cs new file mode 100644 index 0000000..c8e8ed3 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.cs @@ -0,0 +1,177 @@ +using GameArchives; +using GameArchives.Common; +using GameArchives.XISO; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibArchiveExplorer +{ + public partial class EditorWindow : Form + { + private AbstractPackage _pkg; + private List _allFiles; + + public EditorWindow(AbstractPackage pkg) + { + InitializeComponent(); + _pkg = pkg; + Resize += (o,e) => discUsageGraphic.Invalidate(); + LoadPackage(); + } + + /// + /// Draws a graphic that looks like the old Disk Defragmenter disk usage image. + /// + /// + /// + private void DrawGraphic(object sender, PaintEventArgs evt) + { + evt.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; + foreach (var file in _allFiles ?? new List()) + { + var rect = new RectangleF + { + X = file.DataLocation * discUsageGraphic.Width / (float)_pkg.Size, + Y = 0, + Height = discUsageGraphic.Height, + Width = file.Size * discUsageGraphic.Width / (float)_pkg.Size + }; + evt.Graphics.FillRectangle(Brushes.Gray, rect); + } + evt.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + foreach (ListViewItem f in listView1.SelectedItems) + { + var file = f.Tag as OffsetFile; + var rect = new RectangleF + { + X = file.DataLocation * discUsageGraphic.Width / (float)_pkg.Size, + Y = -1, + Height = discUsageGraphic.Height + 2, + Width = Math.Max(file.Size * discUsageGraphic.Width / (float)_pkg.Size, 1) + }; + evt.Graphics.FillRectangle(Brushes.Black, rect); + } + } + + /// + /// Load the package. + /// + private void LoadPackage() + { + if (_pkg.FileType.IsSubclassOrEqual(typeof(OffsetFile))) + { + discUsageGraphic.Invalidate(); + _allFiles = _pkg.GetAllFiles(); + var totalSize = _allFiles.Sum((f) => f.Size); + discUsageBar.Value = ((int)(100 * totalSize / _pkg.Size)).Clamp(discUsageBar.Minimum, discUsageBar.Maximum); + _allFiles.Sort((f, f2) => Math.Sign(f.DataLocation - f2.DataLocation)); + _allFiles.ForEach(f => + listView1.Items.Add(new ListViewItem(new string[] { f.Name }) + { + Tag = f + })); + + lblPackageSize.Text = _pkg.Size.HumanReadableFileSize(); + lblTotalFiles.Text = _allFiles.Count.ToString(); + lblTotalFileSize.Text = totalSize.HumanReadableFileSize(); + actionsGroupBox.Enabled = _pkg.Writeable; + } + else + { + throw new NotImplementedException("Editor support is not implemented for this package type"); + } + } + + private void SelectFileAtByte(long b) + { + foreach(ListViewItem item in listView1.SelectedItems) + { + item.Selected = false; + item.Focused = false; + } + foreach(ListViewItem item in listView1.Items) + { + var file = item.Tag as OffsetFile; + if(file.DataLocation <= b && file.DataLocation + file.Size >= b) + { + listView1.FocusedItem = item; + item.Selected = true; + item.Focused = true; + item.EnsureVisible(); + break; + } + } + } + + /// + /// Closes the currently opened package. + /// + private void ClosePackage() + { + _pkg = null; + listView1.Items.Clear(); + _allFiles?.Clear(); + discUsageGraphic.Invalidate(); + discUsageBar.Value = 0; + } + + + private void toolStripMenuItem1_Click(object sender, EventArgs e) + { + Close(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + discUsageGraphic.Invalidate(); + } + + private void discUsageGraphic_Click(object sender, MouseEventArgs e) + { + SelectFileAtByte((e as MouseEventArgs).X * _pkg.Size / discUsageGraphic.Width); + } + + private void button1_Click(object sender, EventArgs e) + { + if(listView1.SelectedItems.Count != 1) + { + MessageBox.Show(this, "Please select only one item."); + return; + } + var file = listView1.SelectedItems[0].Tag as OffsetFile; + var x = new OpenFileDialog(); + if(x.ShowDialog() == DialogResult.OK) + { + var newFile = Util.LocalFile(x.FileName); + if(MessageBox.Show("This will PERMANENTLY modify the archive." + +Environment.NewLine+"Are you sure you want to continue?","Confirm Action", MessageBoxButtons.YesNo) + == DialogResult.Yes) + { + try + { + if((_pkg as MutablePackage)?.FileReplaceCheck(file, newFile) == true + && (_pkg as MutablePackage)?.TryReplaceFile(file, newFile) == true) + { + MessageBox.Show("Successfully replaced."); + } + else + { + throw new Exception("Failed"); + } + } + catch(Exception ex) + { + MessageBox.Show(ex.Message); + } + } + } + } + } +} diff --git a/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.resx b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/EditorWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dependencies/GameArchives/LibArchiveExplorer/Extensions.cs b/Dependencies/GameArchives/LibArchiveExplorer/Extensions.cs new file mode 100644 index 0000000..30adc90 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/Extensions.cs @@ -0,0 +1,46 @@ +using GameArchives; +using System; +using System.Collections.Generic; + +namespace LibArchiveExplorer +{ + static class Extensions + { + public static string HumanReadableFileSize(this long size) + { + if (size > (1024 * 1024 * 1024)) + { + return (size / (double)(1024 * 1024 * 1024)).ToString("F") + " GiB"; + } + else if (size > (1024 * 1024)) + { + return (size / (double)(1024 * 1024)).ToString("F") + " MiB"; + } + else if (size > 1024) + { + return (size / 1024.0).ToString("F") + " KiB"; + } + else + { + return size.ToString() + " B"; + } + } + + public static bool IsSubclassOrEqual(this Type type, Type other) + { + return type.IsSubclassOf(other) || type == other; + } + + public static int Clamp(this int value, int min, int max) + { + if (value < min) return min; + if (value > max) return max; + return value; + } + + public static Tuple GetLargestFreeBlock(this AbstractPackage pkg) + { + return new Tuple(0, 0); + } + } +} diff --git a/Dependencies/GameArchives/LibArchiveExplorer/FolderSelectDialog.cs b/Dependencies/GameArchives/LibArchiveExplorer/FolderSelectDialog.cs new file mode 100644 index 0000000..20a8234 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/FolderSelectDialog.cs @@ -0,0 +1,154 @@ +using System; +using System.Windows.Forms; + +// ------------------------------------------------------------------ +// Wraps System.Windows.Forms.OpenFileDialog to make it present +// a vista-style dialog. +// ------------------------------------------------------------------ + +namespace FolderSelect +{ + /// + /// Wraps System.Windows.Forms.OpenFileDialog to make it present + /// a vista-style dialog. + /// + public class FolderSelectDialog + { + // Wrapped dialog + System.Windows.Forms.OpenFileDialog ofd = null; + + /// + /// Default constructor + /// + public FolderSelectDialog() + { + ofd = new System.Windows.Forms.OpenFileDialog(); + + ofd.Filter = "Folders|\n"; + ofd.AddExtension = false; + ofd.CheckFileExists = false; + ofd.DereferenceLinks = true; + ofd.Multiselect = false; + } + + #region Properties + + /// + /// Gets/Sets the initial folder to be selected. A null value selects the current directory. + /// + public string InitialDirectory + { + get { return ofd.InitialDirectory; } + set { ofd.InitialDirectory = value == null || value.Length == 0 ? Environment.CurrentDirectory : value; } + } + + /// + /// Gets/Sets the title to show in the dialog + /// + public string Title + { + get { return ofd.Title; } + set { ofd.Title = value == null ? "Select a folder" : value; } + } + + /// + /// Gets the selected folder + /// + public string FileName + { + get { return ofd.FileName; } + } + + #endregion + + #region Methods + + /// + /// Shows the dialog + /// + /// True if the user presses OK else false + public bool ShowDialog() + { + return ShowDialog(IntPtr.Zero); + } + + /// + /// Shows the dialog + /// + /// Handle of the control to be parent + /// True if the user presses OK else false + public bool ShowDialog(IntPtr hWndOwner) + { + bool flag = false; + + if (Environment.OSVersion.Version.Major >= 6) + { + var r = new Reflector("System.Windows.Forms"); + + uint num = 0; + Type typeIFileDialog = r.GetType("FileDialogNative.IFileDialog"); + object dialog = r.Call(ofd, "CreateVistaDialog"); + r.Call(ofd, "OnBeforeVistaDialog", dialog); + + uint options = (uint)r.CallAs(typeof(System.Windows.Forms.FileDialog), ofd, "GetOptions"); + options |= (uint)r.GetEnum("FileDialogNative.FOS", "FOS_PICKFOLDERS"); + r.CallAs(typeIFileDialog, dialog, "SetOptions", options); + + object pfde = r.New("FileDialog.VistaDialogEvents", ofd); + object[] parameters = new object[] { pfde, num }; + r.CallAs2(typeIFileDialog, dialog, "Advise", parameters); + num = (uint)parameters[1]; + try + { + int num2 = (int)r.CallAs(typeIFileDialog, dialog, "Show", hWndOwner); + flag = 0 == num2; + } + finally + { + r.CallAs(typeIFileDialog, dialog, "Unadvise", num); + GC.KeepAlive(pfde); + } + } + else + { + var fbd = new FolderBrowserDialog(); + fbd.Description = this.Title; + fbd.SelectedPath = this.InitialDirectory; + fbd.ShowNewFolderButton = false; + if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK) return false; + ofd.FileName = fbd.SelectedPath; + flag = true; + } + + return flag; + } + + #endregion + } + + /// + /// Creates IWin32Window around an IntPtr + /// + public class WindowWrapper : System.Windows.Forms.IWin32Window + { + /// + /// Constructor + /// + /// Handle to wrap + public WindowWrapper(IntPtr handle) + { + _hwnd = handle; + } + + /// + /// Original ptr + /// + public IntPtr Handle + { + get { return _hwnd; } + } + + private IntPtr _hwnd; + } + +} diff --git a/Dependencies/GameArchives/LibArchiveExplorer/LibArchiveExplorer.csproj b/Dependencies/GameArchives/LibArchiveExplorer/LibArchiveExplorer.csproj new file mode 100644 index 0000000..414393f --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/LibArchiveExplorer.csproj @@ -0,0 +1,25 @@ + + + netstandard2.0 + Library + false + true + true + + + + UserControl + + + + + + + + + + all + + + + \ No newline at end of file diff --git a/Dependencies/GameArchives/LibArchiveExplorer/PackageManager.cs b/Dependencies/GameArchives/LibArchiveExplorer/PackageManager.cs new file mode 100644 index 0000000..49d1805 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/PackageManager.cs @@ -0,0 +1,70 @@ +using GameArchives; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LibArchiveExplorer +{ + public class PackageManager + { + private static PackageManager _pm; + public static PackageManager GetInstance() + { + if(_pm == null) + { + return (_pm = new PackageManager()); + } + return _pm; + } + + public bool Ready { get; private set; } + + public Func> Loader { get; set; } + + private System.Windows.Forms.ToolStripStatusLabel statusLabel; + private System.Windows.Forms.ToolStripStatusLabel spinner; + private PackageManager() + { + Ready = true; + } + + public System.Windows.Forms.ToolStripStatusLabel Spinner + { + set { spinner = value; } + } + public System.Windows.Forms.ToolStripStatusLabel StatusLabel + { + set { statusLabel = value; } + } + + public void SetReady() + { + Ready = true; + if(spinner != null) + spinner.Visible = false; + if (statusLabel != null) + statusLabel.Text = "Ready."; + } + + public void SetBusyState(string busyState) + { + Ready = false; + if (spinner != null) + spinner.Visible = true; + if (statusLabel != null) + statusLabel.Text = busyState; + } + + public async void LoadFile(IFile f, PackageView owner = null) + { + if(Loader == null) return; + var pkgView = await Loader(f); + if(owner != null && pkgView != null) + { + owner.AddChildPackage(pkgView); + } + } + } +} diff --git a/Dependencies/GameArchives/LibArchiveExplorer/PackageView.Designer.cs b/Dependencies/GameArchives/LibArchiveExplorer/PackageView.Designer.cs new file mode 100644 index 0000000..05277fe --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/PackageView.Designer.cs @@ -0,0 +1,279 @@ +namespace LibArchiveExplorer +{ + partial class PackageView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PackageView)); + this.label1 = new System.Windows.Forms.Label(); + this.fileViewContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.extractSelectedItems = new System.Windows.Forms.ToolStripMenuItem(); + this.openSelectedArchiveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.largeImageList = new System.Windows.Forms.ImageList(this.components); + this.smallImageList = new System.Windows.Forms.ImageList(this.components); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.fileView = new System.Windows.Forms.ListView(); + this.nameColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.typeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.sizeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.fileInspectorTabControl = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.filePropertyGrid = new System.Windows.Forms.PropertyGrid(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.openEditorButton = new System.Windows.Forms.Button(); + this.printExtendedInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.fileViewContextMenu.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.fileInspectorTabControl.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(0, 0); + this.label1.Margin = new System.Windows.Forms.Padding(0); + this.label1.Name = "label1"; + this.label1.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4); + this.label1.Size = new System.Drawing.Size(29, 21); + this.label1.TabIndex = 5; + this.label1.Text = "Path"; + // + // fileViewContextMenu + // + this.fileViewContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.extractSelectedItems, + this.openSelectedArchiveToolStripMenuItem, + this.printExtendedInfoToolStripMenuItem}); + this.fileViewContextMenu.Name = "fileViewContextMenu"; + this.fileViewContextMenu.Size = new System.Drawing.Size(197, 92); + // + // extractSelectedItems + // + this.extractSelectedItems.Name = "extractSelectedItems"; + this.extractSelectedItems.Size = new System.Drawing.Size(196, 22); + this.extractSelectedItems.Text = "Extract selected items..."; + this.extractSelectedItems.Click += new System.EventHandler(this.extractItemsToolStripMenuItem_Click); + // + // openSelectedArchiveToolStripMenuItem + // + this.openSelectedArchiveToolStripMenuItem.Name = "openSelectedArchiveToolStripMenuItem"; + this.openSelectedArchiveToolStripMenuItem.Size = new System.Drawing.Size(196, 22); + this.openSelectedArchiveToolStripMenuItem.Text = "Open selected archive"; + this.openSelectedArchiveToolStripMenuItem.Click += new System.EventHandler(this.openSelectedArchiveToolStripMenuItem_Click); + // + // largeImageList + // + this.largeImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("largeImageList.ImageStream"))); + this.largeImageList.TransparentColor = System.Drawing.Color.Transparent; + this.largeImageList.Images.SetKeyName(0, "Folder_large.png"); + this.largeImageList.Images.SetKeyName(1, "File_large.png"); + // + // smallImageList + // + this.smallImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("smallImageList.ImageStream"))); + this.smallImageList.TransparentColor = System.Drawing.Color.Transparent; + this.smallImageList.Images.SetKeyName(0, "Folder_small.png"); + this.smallImageList.Images.SetKeyName(1, "File_small.png"); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel1.Location = new System.Drawing.Point(29, 0); + this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(643, 26); + this.flowLayoutPanel1.TabIndex = 6; + // + // fileView + // + this.fileView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.nameColumn, + this.typeColumn, + this.sizeColumn}); + this.fileView.ContextMenuStrip = this.fileViewContextMenu; + this.fileView.Dock = System.Windows.Forms.DockStyle.Fill; + this.fileView.FullRowSelect = true; + this.fileView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.fileView.HideSelection = false; + this.fileView.LargeImageList = this.largeImageList; + this.fileView.Location = new System.Drawing.Point(0, 0); + this.fileView.Name = "fileView"; + this.fileView.Size = new System.Drawing.Size(430, 388); + this.fileView.SmallImageList = this.smallImageList; + this.fileView.TabIndex = 7; + this.fileView.UseCompatibleStateImageBehavior = false; + this.fileView.View = System.Windows.Forms.View.Details; + this.fileView.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.fileView_ItemSelectionChanged); + this.fileView.DoubleClick += new System.EventHandler(this.fileView_DoubleClick); + // + // nameColumn + // + this.nameColumn.Text = "Name"; + this.nameColumn.Width = 270; + // + // typeColumn + // + this.typeColumn.Text = "Type"; + // + // sizeColumn + // + this.sizeColumn.Text = "Size"; + this.sizeColumn.Width = 80; + // + // splitContainer1 + // + this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + this.splitContainer1.Location = new System.Drawing.Point(3, 32); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.fileView); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.fileInspectorTabControl); + this.splitContainer1.Size = new System.Drawing.Size(669, 388); + this.splitContainer1.SplitterDistance = 430; + this.splitContainer1.TabIndex = 11; + // + // fileInspectorTabControl + // + this.fileInspectorTabControl.Controls.Add(this.tabPage1); + this.fileInspectorTabControl.Controls.Add(this.tabPage2); + this.fileInspectorTabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.fileInspectorTabControl.Location = new System.Drawing.Point(0, 0); + this.fileInspectorTabControl.Name = "fileInspectorTabControl"; + this.fileInspectorTabControl.SelectedIndex = 0; + this.fileInspectorTabControl.Size = new System.Drawing.Size(235, 388); + this.fileInspectorTabControl.TabIndex = 10; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.filePropertyGrid); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(227, 362); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Properties"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // filePropertyGrid + // + this.filePropertyGrid.Dock = System.Windows.Forms.DockStyle.Fill; + this.filePropertyGrid.HelpVisible = false; + this.filePropertyGrid.Location = new System.Drawing.Point(3, 3); + this.filePropertyGrid.Name = "filePropertyGrid"; + this.filePropertyGrid.Size = new System.Drawing.Size(221, 356); + this.filePropertyGrid.TabIndex = 9; + this.filePropertyGrid.ToolbarVisible = false; + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.openEditorButton); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(227, 362); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Tools"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // openEditorButton + // + this.openEditorButton.Location = new System.Drawing.Point(6, 6); + this.openEditorButton.Name = "openEditorButton"; + this.openEditorButton.Size = new System.Drawing.Size(75, 23); + this.openEditorButton.TabIndex = 0; + this.openEditorButton.Text = "Open Editor"; + this.openEditorButton.UseVisualStyleBackColor = true; + this.openEditorButton.Click += new System.EventHandler(this.openEditorButton_Click); + // + // printExtendedInfoToolStripMenuItem + // + this.printExtendedInfoToolStripMenuItem.Name = "printExtendedInfoToolStripMenuItem"; + this.printExtendedInfoToolStripMenuItem.Size = new System.Drawing.Size(196, 22); + this.printExtendedInfoToolStripMenuItem.Text = "Print extended info"; + this.printExtendedInfoToolStripMenuItem.Click += new System.EventHandler(this.printExtendedInfoToolStripMenuItem_Click); + // + // PackageView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.label1); + this.Controls.Add(this.flowLayoutPanel1); + this.Margin = new System.Windows.Forms.Padding(0); + this.Name = "PackageView"; + this.Size = new System.Drawing.Size(675, 423); + this.fileViewContextMenu.ResumeLayout(false); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.fileInspectorTabControl.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.ContextMenuStrip fileViewContextMenu; + private System.Windows.Forms.ToolStripMenuItem extractSelectedItems; + private System.Windows.Forms.ImageList largeImageList; + private System.Windows.Forms.ImageList smallImageList; + private System.Windows.Forms.ToolStripMenuItem openSelectedArchiveToolStripMenuItem; + private System.Windows.Forms.ListView fileView; + private System.Windows.Forms.ColumnHeader nameColumn; + private System.Windows.Forms.ColumnHeader typeColumn; + private System.Windows.Forms.ColumnHeader sizeColumn; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.TabControl fileInspectorTabControl; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.PropertyGrid filePropertyGrid; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.Button openEditorButton; + private System.Windows.Forms.ToolStripMenuItem printExtendedInfoToolStripMenuItem; + } +} diff --git a/Dependencies/GameArchives/LibArchiveExplorer/PackageView.cs b/Dependencies/GameArchives/LibArchiveExplorer/PackageView.cs new file mode 100644 index 0000000..e7bb6f8 --- /dev/null +++ b/Dependencies/GameArchives/LibArchiveExplorer/PackageView.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.ComponentModel.Design; +using GameArchives; +using System.IO; +using FolderSelect; + +namespace LibArchiveExplorer +{ + [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] + public partial class PackageView : UserControl + { + private IDirectory currentDirectory; + private AbstractPackage currentPackage; + + private List children; + private PackageManager pm; + private PackageView parent = null; + + private EditorWindow ew; + + public delegate void FileOpenEventHandler(IFile file); + public delegate void RemoveTabEventHandler(TabPage t); + + public event FileOpenEventHandler OnFileOpen; + public event RemoveTabEventHandler OnRemoveTab; + + public PackageView(AbstractPackage pkg, PackageManager pm) + { + InitializeComponent(); + InitCustomComponents(); + + this.pm = pm; + children = new List(0); + currentPackage = pkg; + currentDirectory = currentPackage.RootDirectory; + filePropertyGrid.SelectedObject = currentPackage; + ResetBreadcrumbs(); + FillFileView(); + } + + private void InitCustomComponents() + { + this.filePropertyGrid.ToolbarVisible = false; + } + + /// + /// Sets the display mode of the files in the view (e.g., icons, details, list...) + /// + public void SetView(View v) + { + fileView.View = v; + } + + /// + /// Navigates the view to the given directory. + /// + private void SetCurrentDir(IDirectory dir) + { + currentDirectory = dir; + FillFileView(); + ResetBreadcrumbs(); + } + + /// + /// Add a package as a child of this package. + /// This means the given package will be closed if this package is closed. + /// + public void AddChildPackage(PackageView p) + { + this.children.Add(p); + p.SetParentPackage(this); + } + + private void RemoveChildPackage(PackageView p) + { + this.children.Remove(p); + } + + private void SetParentPackage(PackageView p) + { + parent = p; + } + + public void Unload() + { + parent?.RemoveChildPackage(this); + ew?.Close(); + var childrenFixed = children.ToArray(); + foreach(var pkg in childrenFixed) + { + pkg.Unload(); + } + currentPackage?.Dispose(); + currentPackage = null; + currentDirectory = null; + FillFileView(); + ResetBreadcrumbs(); + OnRemoveTab?.Invoke(Tag as TabPage); + } + + private void FillFileView() + { + fileView.Items.Clear(); + if (currentDirectory != null) + { + foreach (var dir in currentDirectory.Dirs) + { + var item = new ListViewItem(new string[] { dir.Name, "Directory" }); + item.Tag = dir; + item.ImageIndex = 0; + fileView.Items.Add(item); + } + foreach (var file in currentDirectory.Files) + { + var item = new ListViewItem(new string[] { file.Name, "File", file.Size.HumanReadableFileSize() }); + item.Tag = file; + item.ImageIndex = 1; + fileView.Items.Add(item); + } + } + } + + private void ResetBreadcrumbs() + { + var dir = currentDirectory; + var i = 1; + var breadcrumbs = new List