New Language Tool
This commit is contained in:
@ -1,86 +0,0 @@
|
||||
undefined,UNDEFINED
|
||||
hello.world,Hello World!
|
||||
character.death.name,"Santa Muerte"
|
||||
character.penny.name,Penny
|
||||
|
||||
scene.1.1,"...Huh? Where am I?"
|
||||
scene.1.2,"Relax child, come forward, it is time."
|
||||
scene.1.3,"Who said that? Where is that voice coming from?"
|
||||
scene.1.4,"Hello, and welcome to the other side wanderer."
|
||||
scene.1.5,"Other side? Wait that robe! You don't mean?"
|
||||
scene.1.6,"Yeah let's speed things up here a bit. Normally I go on script but short on time right now unfortunately."
|
||||
scene.1.7,"You died, dead, passed on, kaput. This is the space between spaces. You may be going up, you may be going down, that's not my choice, I'm just here to guide you."
|
||||
scene.1.8,"...Are you?"
|
||||
scene.1.9,"Yes, some call me the Grim Reaper, some Muerte, and a long time ago it was Torva messor."
|
||||
scene.1.10,"Nowadays most people others just call me Death, but I prefer Nami, short for Izanami."
|
||||
scene.1.11,"Truth be told I am not the reason you are here, I am just here to guide you, don't know why I keep getting lumped with this bad reputation of killing people."
|
||||
scene.1.12,"Wait, so I am dead? For real? This has to be some kind of misunderstanding-wait I must be dreaming, that's it."
|
||||
scene.1.121,"Oh no this can't be happening, this can't be real..."
|
||||
scene.1.13,"If I had a penny for every time...
|
||||
No, don't get it wrong, you are meant to be here."
|
||||
scene.1.131,"I can't be.. you gotta send me back! How did I die?"
|
||||
scene.1.132,"I don't know. Regardless, I can't send you back to your world. We are getting off topic anyway."
|
||||
scene.1.133,"What?"
|
||||
scene.1.134,"*ahem* I have a request of you child."
|
||||
scene.1.14,"Me? Help you? Unless you're taking me back to my home I don't think you can convince me to help the likes of you."
|
||||
scene.1.141,"Yes... See, normally I'd just take you to Charon. It is his role to take the newcomers where they need to go."
|
||||
scene.1.142,"You know how it goes, I introduce you to Charon, you pay a coin, jump on a boat, and then you're not my problem any more."
|
||||
scene.1.15,"You mean send me down the river styx? You're not helping your case."
|
||||
scene.1.16,"Yes, well I would normally do that, but at the moment I have a bit of a problem with capacity."
|
||||
scene.1.17,"Capacity? What kind of capacity issue?"
|
||||
scene.1.18,"I manage a few worlds, not just the one that you come from."
|
||||
scene.1.19,"In your world, people rely on technology and their own ability to progress civilization."
|
||||
scene.1.20,"In another world, I manage people who raise and tame small pocket sized creatures with different abilities to progress their civilization."
|
||||
scene.1.21,"But one world I manage has been having some real troubles lately."
|
||||
scene.1.22,"This world contains humans alongside other intelligent creatures and species. They would be analagous to the medieval times in your world."
|
||||
scene.1.23,"So far they have managed to keep a good balance by having some creatures weild weapons, and some use magical powers."
|
||||
scene.1.24,"But lately there has been more cases of stronger creatures killing off the human population."
|
||||
scene.1.25,"It's causing me to work overtime just to make sure I can get everyone where they need to go."
|
||||
scene.1.26,"You have to work overtime?"
|
||||
scene.1.27,"The benefits here are really good, my union gives us time and a half for overtime we do."
|
||||
scene.1.28,"Death has unionized? That sounds horrible."
|
||||
scene.1.29,"Yes I did, and please just call me Nami. My union is starting to threaten a strike and I need to try and prevent that."
|
||||
scene.1.30,"I haven't been on strike since the 1940's when we had our last capacity issue."
|
||||
scene.1.31,"The union negotiated a great dental plan after that. But we need to try and avoid striking this time."
|
||||
scene.1.32,"Okay but I don't know how you think I can help."
|
||||
scene.1.33,"It's easy. Now understand that I cannot send you back to your world, that is out of my control."
|
||||
scene.1.34,"But there are no rules about you being sent to another world."
|
||||
scene.1.35,"So, I send you to the medieval world, you get another crack at life and perhaps you can assist me in finding out how to stop all the deaths."
|
||||
scene.1.36,"So, Nami, you want me to go to a world I don't know, that has monsters and a problem with lots of death, stuck in the medieval times, just to help out literal death?"
|
||||
scene.1.37,"Not to mention I won't know anyone, I won't understand their language and don't know their culture."
|
||||
scene.1.38,"I'll put it bluntly Nami, it sounds like I would be signing up for a short, miserable, lonely life, just for a chance to help you out."
|
||||
scene.1.39,"That's great, thanks for offering to help out!"
|
||||
scene.1.40,"I don't have a choice do I?"
|
||||
scene.1.41,"No, besides we have already started. Now, stand still and take a deep breath I am going to send you over to the other world now."
|
||||
scene.1.42,"I feel really tired all of a sudden... Wait does the Grim Reaper even have any kind of powers?"
|
||||
scene.1.43,"Of course I do, now open your eyes..."
|
||||
|
||||
scene.2.1,"This scene has you waking in the new world"
|
||||
scene.3.1,"This is the scene to prep you for the first game"
|
||||
scene.4.1,"First Poker Game with friendlies"
|
||||
scene.5.1,"After first game, wind up maybe shop instructions or something"
|
||||
scene.6.1,"Talk with death probably, check in on you, etc."
|
||||
scene.7.1,"Pre-Orc Battle"
|
||||
scene.8.1,"Orc Battle"
|
||||
scene.9.1,"Immediately Post Orc Battle"
|
||||
scene.10.1,"Morning after orc battle and some foreshadowing"
|
||||
scene.11.1,"Pre battle with theif"
|
||||
scene.12.1,"Battle with theif"
|
||||
unknown1,"There needs to be the big bad here."
|
||||
scene.13.1,"After battle with theif, things cool off a bit."
|
||||
scene.14.1,"Harem times maybe"
|
||||
scene.15.1,"Harem times interrupted by some chaos"
|
||||
scene.16.1,"I'm putting chaos here but this scene is probably redundant."
|
||||
scene.17.1,"Chaos battle"
|
||||
scene.18.1,"Post Chaos Battle, things are still gloomy"
|
||||
unknown2,"Another big bad here probably."
|
||||
scene.19.1,"Pre King Arrival, rumours"
|
||||
scene.20.1,"King Arrival, Everyone's annoyed"
|
||||
scene.21.1,"King in the bar, running his mouth"
|
||||
scene.22.1,"King Fight"
|
||||
scene.23.1,"Post King Fight, angry he leaves, town rallies around you"
|
||||
scene.24.1," Go to one of the kingsmen who's working with the big bad, he's worried that the townspeople know more than they let on."
|
||||
unknown3,"Something here has to bring the big bad to town."
|
||||
unknown4,"It's revealed that death knows the big bad",
|
||||
test.1,"Test"
|
||||
test.2,"Test*"
|
Can't render this file because it has a wrong number of fields in line 84.
|
@ -1,21 +0,0 @@
|
||||
undefined,UNDEFINED
|
||||
hello.world,Hello World!
|
||||
character.penny.name,Penny
|
||||
scene.1.1,"日本語パスコん"
|
||||
scene.2.1,"This scene has you waking in the new world"
|
||||
scene.3.1,"This is the scene to prep you for the first game"
|
||||
scene.4.1,"First Poker Game with friendlies"
|
||||
scene.5.1,"After first game, wind up maybe shop instructions or something"
|
||||
scene.6.1,"Talk with death probably, check in on you, etc."
|
||||
scene.7.1,"Pre-Orc Battle"
|
||||
scene.8.1,"Orc Battle"
|
||||
scene.9.1,"Immediately Post Orc Battle"
|
||||
scene.10.1,"Morning after orc battle and some foreshadowing"
|
||||
scene.11.1,"Pre battle with theif"
|
||||
scene.12.1,"Battle with theif"
|
||||
scene.13.1,"After battle with theif, things cool off a bit."
|
||||
scene.14.1,"Harem times maybe"
|
||||
scene.15.1,"Harem times interrupted by some chaos"
|
||||
scene.16.1,"I'm putting chaos here but this scene is probably redundant."
|
||||
scene.17.1,"Chaos battle"
|
||||
scene.18.1,"Post Chaos Battle, things are still gloomy"
|
|
91
assets/games/pokergame/locale/locale.xml
Normal file
91
assets/games/pokergame/locale/locale.xml
Normal file
@ -0,0 +1,91 @@
|
||||
<locale>
|
||||
<language name="en" />
|
||||
<group key="scene">
|
||||
<group key="1">
|
||||
<group key="1">
|
||||
<string lang="en">...Huh? Where am I?</string>
|
||||
</group>
|
||||
</group>
|
||||
<group key="2">
|
||||
<string lang="en">This scene has you waking in the new world</string>
|
||||
</group>
|
||||
<group key="3">
|
||||
<string lang="en">This is the scene to prep you for the first game</string>
|
||||
</group>
|
||||
<group key="4">
|
||||
<string lang="en">First Poker Game with friendlies</string>
|
||||
</group>
|
||||
<group key="5">
|
||||
<string lang="en">After first game, wind up maybe shop instructions or something</string>
|
||||
</group>
|
||||
<group key="6">
|
||||
<string lang="en">Talk with death probably, check in on you, etc.</string>
|
||||
</group>
|
||||
<group key="7">
|
||||
<string lang="en">Pre-Orc Battle</string>
|
||||
</group>
|
||||
<group key="8">
|
||||
<string lang="en">Orc Battle</string>
|
||||
</group>
|
||||
<group key="9">
|
||||
<string lang="en">Immediately Post Orc Battle</string>
|
||||
</group>
|
||||
<group key="10">
|
||||
<string lang="en">Morning after orc battle and some foreshadowing</string>
|
||||
</group>
|
||||
<group key="11">
|
||||
<string lang="en">Pre battle with theif</string>
|
||||
</group>
|
||||
<group key="12">
|
||||
<string lang="en">Battle with theif</string>
|
||||
</group>
|
||||
<group key="13">
|
||||
<string lang="en">There needs to be the big bad here.</string>
|
||||
</group>
|
||||
<group key="14">
|
||||
<string lang="en">After battle with theif, things cool off a bit.</string>
|
||||
</group>
|
||||
<group key="15">
|
||||
<string lang="en">Harem times maybe</string>
|
||||
</group>
|
||||
<group key="16">
|
||||
<string lang="en">Harem times interrupted by some chaos</string>
|
||||
</group>
|
||||
<group key="17">
|
||||
<string lang="en">I'm putting chaos here but this scene is probably redundant.</string>
|
||||
</group>
|
||||
<group key="18">
|
||||
<string lang="en">Chaos battle</string>
|
||||
</group>
|
||||
<group key="19">
|
||||
<string lang="en">Post Chaos Battle, things are still gloomy</string>
|
||||
</group>
|
||||
<group key="20">
|
||||
<string lang="en">Another big bad here probably.</string>
|
||||
</group>
|
||||
<group key="21">
|
||||
<string lang="en">Pre King Arrival, rumours</string>
|
||||
</group>
|
||||
<group key="22">
|
||||
<string lang="en">King Arrival, Everyone's annoyed</string>
|
||||
</group>
|
||||
<group key="23">
|
||||
<string lang="en">King in the bar, running his mouth</string>
|
||||
</group>
|
||||
<group key="24">
|
||||
<string lang="en">King Fight</string>
|
||||
</group>
|
||||
<group key="25">
|
||||
<string lang="en">Post King Fight, angry he leaves, town rallies around you</string>
|
||||
</group>
|
||||
<group key="26">
|
||||
<string lang="en">Go to one of the kingsmen who's working with the big bad, he's worried that the townspeople know more than they let on.</string>
|
||||
</group>
|
||||
<group key="27">
|
||||
<string lang="en">Something here has to bring the big bad to town.</string>
|
||||
</group>
|
||||
<group key="28">
|
||||
<string lang="en">It's revealed that death knows the big bad</string>
|
||||
</group>
|
||||
</group>
|
||||
</locale>
|
@ -1,13 +0,0 @@
|
||||
<root
|
||||
name="UITest"
|
||||
UISprite="ui/UISprite.hpp"
|
||||
UIEmpty="ui/UIEmpty.hpp"
|
||||
UIGrid="ui/UIGrid.hpp"
|
||||
>
|
||||
<UIGrid name="grid" align="stretch stretch 0 0 0 0" rows="2" columns="2">
|
||||
<UISprite name="rect0" grid="stretch stretch 0 0" color="COLOR_RED" />
|
||||
<UISprite name="rect1" grid="stretch stretch 1 0" color="COLOR_BLUE" />
|
||||
<UISprite name="rect2" grid="stretch stretch 0 1" color="COLOR_WHITE" />
|
||||
<UISprite name="rect3" grid="stretch stretch 1 1" color="COLOR_BLACK" />
|
||||
</UIGrid>
|
||||
</root>
|
36
assets/games/pokergame/vn/testvn.txt
Normal file
36
assets/games/pokergame/vn/testvn.txt
Normal file
@ -0,0 +1,36 @@
|
||||
# This is a sample VN Scene that I am creating to create a scene generator.
|
||||
# The scene generator will simply create a series of events, nothing more.
|
||||
# Infact, the scene generator really is just a scene event with trailed events
|
||||
# Generator.
|
||||
|
||||
# Scene name is probably going to be inherited from either the target or the
|
||||
# filename
|
||||
|
||||
# By default the mode we are in is in TEXT mode, unless you explicitly change
|
||||
# the mode. The text mode takes the person, emotion and text string and tries
|
||||
# to convert it to this C++ equivallent code;
|
||||
# new VisualNovelTextboxEvent(vnManager, this->[person]->vnCharacter, this->[person]->[emotion], [text])
|
||||
|
||||
# Here is our first example. We take death, give her an emotion, and write some
|
||||
# text.
|
||||
death:happy: scene.1.1
|
||||
|
||||
# Here, we inherit the existing emotion. I've also omitted the space because it
|
||||
# is just there for show.
|
||||
death:scene.1.1
|
||||
|
||||
# Now let's fade our character in. Fade char in events start like this
|
||||
fade death in quad over 1.0
|
||||
# Could also be written like any of these
|
||||
# fade death out
|
||||
# fade death in
|
||||
# fade death out over 1.0 seconds
|
||||
# fade death in over 1.0 seconds
|
||||
# fade death in linear
|
||||
# fade death out linear over 10 seconds
|
||||
# fade death out over 10
|
||||
# Basically the format just needs to be
|
||||
# fade [character] [in/out] (easing function) (time)
|
||||
# Each time a fade occurs the parameters will be remembered, and used for any
|
||||
# other fade after that, so you just need to define the easing curve once per
|
||||
# scene.
|
94
lint.js
Normal file
94
lint.js
Normal file
@ -0,0 +1,94 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DIR_SOURCES = path.resolve('src');
|
||||
|
||||
const fileGetContents = filePath => fs.readFileSync(filePath, 'utf-8');
|
||||
|
||||
const ensureCopyright = (file, contents) => {
|
||||
if(
|
||||
contents.includes('Copyright (c)') &&
|
||||
contents.includes('MIT')
|
||||
) return;
|
||||
throw new Error(`${file} is missing its copyright!`);
|
||||
}
|
||||
|
||||
const ensurePragma = (file, contents) => {
|
||||
if(contents.includes('#pragma once')) return;
|
||||
throw new Error(`${file} is missing a #pragma once`);
|
||||
}
|
||||
|
||||
|
||||
const fileHandleCpp = filePath => {
|
||||
// Load contents
|
||||
const contents = fileGetContents(filePath);
|
||||
ensureCopyright(filePath, contents);
|
||||
}
|
||||
|
||||
const fileHandleC = filePath => {
|
||||
// Load contents
|
||||
const contents = fileGetContents(filePath);
|
||||
ensureCopyright(filePath, contents);
|
||||
}
|
||||
|
||||
const fileHandleHpp = filePath => {
|
||||
// Load contents
|
||||
const contents = fileGetContents(filePath);
|
||||
|
||||
ensureCopyright(filePath, contents);
|
||||
ensurePragma(filePath, contents);
|
||||
}
|
||||
|
||||
const fileHandleH = filePath => {
|
||||
// Load contents
|
||||
const contents = fileGetContents(filePath);
|
||||
|
||||
ensureCopyright(filePath, contents);
|
||||
ensurePragma(filePath, contents);
|
||||
}
|
||||
|
||||
const fileHandleCmake = filePath => {
|
||||
// Load contents
|
||||
const contents = fileGetContents(filePath);
|
||||
|
||||
// Check for the copyright
|
||||
ensureCopyright(filePath, contents);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const fileScan = filePath => {
|
||||
const ext = path.extname(filePath).replace(/\./g, '');
|
||||
const base = path.basename(filePath);
|
||||
|
||||
if(ext === 'cpp') {
|
||||
fileHandleCpp(filePath);
|
||||
} else if(ext === 'hpp') {
|
||||
fileHandleHpp(filePath);
|
||||
} else if(ext === 'c') {
|
||||
fileHandleC(filePath);
|
||||
} else if(ext === 'h') {
|
||||
fileHandleH(filePath);
|
||||
}else if(base === 'CMakeLists.txt') {
|
||||
fileHandleCmake(filePath);
|
||||
} else {
|
||||
throw new Error(`Unknown file type ${filePath}`);
|
||||
}
|
||||
};
|
||||
|
||||
const dirScan = directory => {
|
||||
const contents = fs.readdirSync(directory);
|
||||
contents.forEach(filePath => {
|
||||
const abs = path.join(directory, filePath);
|
||||
const stat = fs.statSync(abs);
|
||||
if(stat.isDirectory()) {
|
||||
dirScan(abs);
|
||||
} else {
|
||||
fileScan(abs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(() => {
|
||||
dirScan(DIR_SOURCES);
|
||||
})();
|
@ -30,7 +30,7 @@ add_subdirectory(scenes)
|
||||
set(DIR_GAME_ASSETS games/pokergame)
|
||||
tool_texture(texture_test texture_test.png)
|
||||
|
||||
tool_language(language_en ${DIR_GAME_ASSETS}/locale/en.csv)
|
||||
tool_language(locale_poker ${DIR_GAME_ASSETS}/locale/locale.xml)
|
||||
|
||||
tool_tileset(tileset_death texture_death ${DIR_GAME_ASSETS}/characters/death/sheet.png 1 3)
|
||||
tool_tileset(tileset_penny texture_penny ${DIR_GAME_ASSETS}/characters/penny/sheet.png 1 3)
|
||||
@ -39,10 +39,8 @@ tool_truetype(truetype_alice ${DIR_GAME_ASSETS}/font/Alice-Regular.ttf truetype_
|
||||
|
||||
tool_audio(audio_test borrowed/sample_short.wav)
|
||||
|
||||
tool_ui(ui_test ${DIR_GAME_ASSETS}/ui/uitest.xml)
|
||||
|
||||
add_dependencies(${DAWN_TARGET_NAME}
|
||||
language_en
|
||||
locale_poker
|
||||
|
||||
tileset_death
|
||||
tileset_penny
|
||||
@ -52,6 +50,4 @@ add_dependencies(${DAWN_TARGET_NAME}
|
||||
texture_test
|
||||
|
||||
audio_test
|
||||
|
||||
ui_test
|
||||
)
|
@ -1,9 +1,13 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(file)
|
||||
add_subdirectory(locale)
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(file)
|
||||
add_subdirectory(locale)
|
||||
|
||||
if(DAWN_VISUAL_NOVEL)
|
||||
add_subdirectory(visualnovel)
|
||||
endif()
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
# Copyright (c) 2023 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
@ -1,15 +1,15 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(languagegen)
|
||||
|
||||
# Language Tool
|
||||
function(tool_language target in)
|
||||
add_custom_target(${target}
|
||||
COMMAND languagegen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}/${target}"
|
||||
COMMENT "Generating texture ${target} from ${in}"
|
||||
DEPENDS languagegen
|
||||
)
|
||||
endfunction()
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(languagegen)
|
||||
|
||||
# Language Tool
|
||||
function(tool_language target in)
|
||||
add_custom_target(${target}
|
||||
COMMAND languagegen "${DAWN_ASSETS_SOURCE_DIR}/${in}" "${DAWN_ASSETS_BUILD_DIR}"
|
||||
COMMENT "Generating language set ${target} from ${in}"
|
||||
DEPENDS languagegen
|
||||
)
|
||||
endfunction()
|
||||
|
@ -1,25 +1,24 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Texture Build Tool
|
||||
project(languagegen VERSION 1.0)
|
||||
add_executable(languagegen)
|
||||
target_sources(languagegen
|
||||
PRIVATE
|
||||
main.c
|
||||
../../utils/file.c
|
||||
../../utils/image.c
|
||||
../../utils/csv.c
|
||||
)
|
||||
target_include_directories(languagegen
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_libraries(languagegen
|
||||
PUBLIC
|
||||
${DAWN_BUILD_HOST_LIBS}
|
||||
stb
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Texture Build Tool
|
||||
project(languagegen VERSION 2.0)
|
||||
add_executable(languagegen)
|
||||
target_sources(languagegen
|
||||
PRIVATE
|
||||
main.cpp
|
||||
../../utils/file.c
|
||||
../../utils/csv.c
|
||||
../../utils/xml.c
|
||||
)
|
||||
target_include_directories(languagegen
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_libraries(languagegen
|
||||
PUBLIC
|
||||
${DAWN_BUILD_HOST_LIBS}
|
||||
)
|
@ -1,112 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "../../utils/common.h"
|
||||
#include "../../utils/file.h"
|
||||
#include "../../utils/csv.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *file;
|
||||
char path[FILENAME_MAX + 1];
|
||||
csv_t csv;
|
||||
char *in;
|
||||
char *out;
|
||||
char *buffer;
|
||||
char sep = '|';
|
||||
|
||||
if(argc != 3) {
|
||||
printf("Invalid number of arguments\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set up strings
|
||||
in = argv[1];
|
||||
out = argv[2];
|
||||
|
||||
// Normalize slashes
|
||||
fileNormalizeSlashes(in);
|
||||
fileNormalizeSlashes(out);
|
||||
|
||||
// Check the output doesn't already exist
|
||||
sprintf(path, "%s.language", out);
|
||||
// file = fopen(path, "rb");
|
||||
// if(file != NULL) {
|
||||
// fclose(file);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// Read in original CSV string
|
||||
file = fopen(in, "rb");
|
||||
if(file == NULL) {
|
||||
printf("Failed to open file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Seek to end, get length, seek back to start.
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Read in all data
|
||||
buffer = malloc(sizeof(char) * (fileSize + 1));
|
||||
size_t readSize = fread(buffer, 1, fileSize, file);
|
||||
fclose(file);
|
||||
if(readSize < fileSize) {
|
||||
printf("Failed to read all data from CSV\n");
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
buffer[fileSize] = '\0';
|
||||
|
||||
csvParse(buffer, &csv);
|
||||
free(buffer);
|
||||
|
||||
// Prepare output file for writing.
|
||||
sprintf(path, "%s.language", out);
|
||||
fileMkdirp(path);
|
||||
file = fopen(path, "wb");
|
||||
if(file == NULL) {
|
||||
printf("Failed to create output language file\n");
|
||||
csvDispose(&csv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Iterate over the CSV
|
||||
for(int32_t y = 0; y < csv.rowCount; y++) {
|
||||
// Ensure valid line
|
||||
if(csv.cellCounts[y] != 2) {
|
||||
printf("Failed to parse language. Line %i has %i cells instead of 2\n", y, csv.cellCounts);
|
||||
fclose(file);
|
||||
csvDispose(&csv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *key = csvGetCell(&csv, y, 0);
|
||||
char *value = csvGetCell(&csv, y, 1);
|
||||
|
||||
// 23/01/14 - Replace \r in CSV.
|
||||
stringRemoveAll(key, '\r');
|
||||
stringRemoveAll(value, '\r');
|
||||
if(strlen(key) <= 0 || strlen(value) <= 0) {
|
||||
printf("Failed to parse language. Line %i has an invalid string\n", y);
|
||||
fclose(file);
|
||||
csvDispose(&csv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(key, sizeof(char), strlen(key), file);
|
||||
fwrite(&sep, sizeof(char), 1, file);
|
||||
fwrite(value, sizeof(char), strlen(value), file);
|
||||
fwrite(&sep, sizeof(char), 1, file);
|
||||
}
|
||||
|
||||
// Finished writing
|
||||
fclose(file);
|
||||
csvDispose(&csv);
|
||||
|
||||
return 0;
|
||||
}
|
218
src/dawntools/locale/languagegen/main.cpp
Normal file
218
src/dawntools/locale/languagegen/main.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "../../utils/common.h"
|
||||
#include "../../utils/file.h"
|
||||
#include "../../utils/csv.h"
|
||||
#include "../../utils/xml.h"
|
||||
#include <memory.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
struct LanguageString {
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
int32_t parseString(
|
||||
xml_t *stringNode,
|
||||
std::string key,
|
||||
std::map<std::string,std::vector<struct LanguageString>> *strings
|
||||
) {
|
||||
auto attrLang = xmlGetAttributeByName(stringNode, "lang");
|
||||
if(attrLang == -1) {
|
||||
std::cout << "String is missing lang parameter." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string lang(stringNode->attributeDatas[attrLang]);
|
||||
struct LanguageString str;
|
||||
str.key = key;
|
||||
str.value = std::string(stringNode->value);
|
||||
|
||||
auto existing = (*strings).find(lang);
|
||||
if(existing == (*strings).end()) {
|
||||
(*strings).insert(std::make_pair(lang, std::vector<struct LanguageString>()));
|
||||
}
|
||||
(*strings)[lang].push_back(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t parseGroup(
|
||||
xml_t *groupNode,
|
||||
std::string key,
|
||||
std::map<std::string,std::vector<struct LanguageString>> *strings
|
||||
) {
|
||||
int32_t ret;
|
||||
|
||||
auto attrKey = xmlGetAttributeByName(groupNode, "key");
|
||||
if(attrKey == -1) {
|
||||
std::cout << "Group node is missing key" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(key.size() > 0) key += ".";
|
||||
key += std::string(groupNode->attributeDatas[attrKey]);
|
||||
|
||||
for(int32_t i = 0; i < groupNode->childrenCount; i++) {
|
||||
auto c = groupNode->children + i;
|
||||
if(std::string(c->node) == "string") {
|
||||
ret = parseString(c, key, strings);
|
||||
if(ret != 0) return ret;
|
||||
} else if(std::string(c->node) == "group") {
|
||||
ret = parseGroup(c, key, strings);
|
||||
if(ret != 0) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if(argc != 3) {
|
||||
std::cout << "Invalid number of arguments provided to language gen!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *fileInName = argv[1];
|
||||
fileNormalizeSlashes(fileInName);
|
||||
|
||||
FILE *fileIn = fopen(fileInName, "rb");
|
||||
if(fileIn == NULL) {
|
||||
std::cout << "Failed to open input file " << fileInName << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto size = assetReadString(fileIn, NULL);
|
||||
char *buffer = (char *)malloc(sizeof(char) * size);
|
||||
if(buffer == NULL) {
|
||||
std::cout << "Failed to allocate memory for locale string XML" << std::endl;
|
||||
fclose(fileIn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assetReadString(fileIn, buffer);
|
||||
fclose(fileIn);
|
||||
|
||||
xml_t xml;
|
||||
xmlLoad(&xml, buffer);
|
||||
free(buffer);
|
||||
|
||||
// Begin parsing. Start by looking for the <language> tags
|
||||
std::vector<std::string> languages;
|
||||
for(int32_t i = 0; i < xml.childrenCount; i++) {
|
||||
auto c = xml.children + i;
|
||||
if(std::string(c->node) != "language") continue;
|
||||
auto attrName = xmlGetAttributeByName(c, "name");
|
||||
|
||||
if(attrName == -1) {
|
||||
std::cout << "Missing name param on language node" << std::endl;
|
||||
xmlDispose(&xml);
|
||||
return 1;
|
||||
}
|
||||
languages.push_back(std::string(c->attributeDatas[attrName]));
|
||||
}
|
||||
|
||||
// Now begin actually parsing
|
||||
std::map<std::string, std::vector<struct LanguageString>> strings;
|
||||
for(int32_t i = 0; i < xml.childrenCount; i++) {
|
||||
auto c = xml.children + i;
|
||||
if(std::string(c->node) == "group") {
|
||||
auto ret = parseGroup(c, "", &strings);
|
||||
if(ret != 0) {
|
||||
xmlDispose(&xml);
|
||||
return ret;
|
||||
}
|
||||
} else if(std::string(c->node) == "string") {
|
||||
std::cout << "String cannot be a root node" << std::endl;
|
||||
xmlDispose(&xml);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
xmlDispose(&xml);
|
||||
|
||||
// Now we validate each lang has each key.
|
||||
std::vector<std::string> keys;
|
||||
|
||||
auto it = strings.begin();
|
||||
while(it != strings.end()) {
|
||||
auto it2 = it->second.begin();
|
||||
while(it2 != it->second.end()) {
|
||||
auto key = it2->key;
|
||||
auto exist = std::find(keys.begin(), keys.end(), key);
|
||||
if(exist == keys.end()) {
|
||||
keys.push_back(key);
|
||||
}
|
||||
it2++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
// Now we actually parse each string, validating as we go.
|
||||
it = strings.begin();
|
||||
while(it != strings.end()) {
|
||||
std::vector<std::string> itKeys;
|
||||
|
||||
std::string bufferOut = "";
|
||||
|
||||
auto it2 = it->second.begin();
|
||||
while(it2 != it->second.end()) {
|
||||
auto l = *it2;
|
||||
itKeys.push_back(l.key);
|
||||
bufferOut += l.key + "|" + l.value + "|";
|
||||
it2++;
|
||||
}
|
||||
|
||||
std::string filenameOut(argv[2]);
|
||||
filenameOut += "/nlanguage_" + it->first + ".language";
|
||||
|
||||
char *filenameOutC = (char *)malloc(sizeof(char) * (filenameOut.size() + 1));
|
||||
if(filenameOutC == NULL) {
|
||||
std::cout << "Failed to allocate filename memory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
strcpy(filenameOutC, filenameOut.c_str());
|
||||
fileNormalizeSlashes(filenameOutC);
|
||||
|
||||
fileMkdirp(filenameOutC);
|
||||
FILE *fileOut = fopen(filenameOutC, "wb");
|
||||
free(filenameOutC);
|
||||
if(fileOut == NULL) {
|
||||
std::cout << "Failed to create output file " << filenameOut << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *strOut = bufferOut.c_str();
|
||||
fwrite(strOut, sizeof(char), strlen(strOut), fileOut);
|
||||
fclose(fileOut);
|
||||
|
||||
auto it3 = keys.begin();
|
||||
while(it3 != keys.end()) {
|
||||
auto key = *it3;
|
||||
auto inIt = std::find(itKeys.begin(), itKeys.end(), key);
|
||||
if(inIt == itKeys.end()) {
|
||||
std::cout << "Locale " << it->first << " missing key " << key << std::endl;
|
||||
}
|
||||
it3++;
|
||||
}
|
||||
|
||||
if(itKeys.size() != keys.size()) {
|
||||
std::cout << "Locale is missing some keys, see above" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,210 +1,211 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
bool insideTag = false;
|
||||
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
|
||||
xml->childrenCount = 0;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_DOING_NOTHING:
|
||||
// Look for either an opening tag (<) or a word for a value.
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(insideTag) {
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
doing = XML_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
doing = XML_PARSING_VALUE;
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->node = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(bufferLength > 0) {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeNames[xml->attributeCount++] = buffer;
|
||||
xml->attributeDatas[xml->attributeCount] = NULL;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeDatas[xml->attributeCount - 1] = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSING_CLOSE;
|
||||
buffer[bufferLength] = '\0';
|
||||
bufferLength = 0;
|
||||
xml->value = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
free(buffer);
|
||||
return i;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return i;
|
||||
}
|
||||
|
||||
void xmlLoad(xml_t *xml, char *data) {
|
||||
xmlLoadChild(xml, data, 0);
|
||||
}
|
||||
|
||||
void xmlDispose(xml_t *xml) {
|
||||
uint8_t i;
|
||||
|
||||
// Dispose children recursively
|
||||
for(i = 0; i < xml->childrenCount; i++) {
|
||||
xmlDispose(xml->children + i);
|
||||
}
|
||||
|
||||
// Free children array.
|
||||
free(xml->children);
|
||||
|
||||
// Dispose attributes
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
free(xml->attributeNames[i]);
|
||||
if((xml->attributeDatas + i) != NULL) {
|
||||
free(xml->attributeDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(xml->node);
|
||||
if(xml-> value != NULL) free(xml->value);
|
||||
}
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
|
||||
int16_t i;
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
if(strcmp(xml->attributeNames[i], name) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool xmlIsWhitespace(char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
bool insideTag = false;
|
||||
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
|
||||
xml->childrenCount = 0;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_DOING_NOTHING:
|
||||
// Look for either an opening tag (<) or a word for a value.
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(insideTag) {
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
doing = XML_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
doing = XML_PARSING_VALUE;
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->node = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(bufferLength > 0) {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeNames[xml->attributeCount++] = buffer;
|
||||
xml->attributeDatas[xml->attributeCount] = NULL;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeDatas[xml->attributeCount - 1] = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSING_CLOSE;
|
||||
buffer[bufferLength] = '\0';
|
||||
bufferLength = 0;
|
||||
xml->value = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
free(buffer);
|
||||
return i;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return i;
|
||||
}
|
||||
|
||||
void xmlLoad(xml_t *xml, char *data) {
|
||||
xmlLoadChild(xml, data, 0);
|
||||
}
|
||||
|
||||
void xmlDispose(xml_t *xml) {
|
||||
uint8_t i;
|
||||
|
||||
// Dispose children recursively
|
||||
for(i = 0; i < xml->childrenCount; i++) {
|
||||
xmlDispose(xml->children + i);
|
||||
}
|
||||
|
||||
// Free children array.
|
||||
free(xml->children);
|
||||
|
||||
// Dispose attributes
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
free(xml->attributeNames[i]);
|
||||
if((xml->attributeDatas + i) != NULL) {
|
||||
free(xml->attributeDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(xml->node);
|
||||
if(xml-> value != NULL) free(xml->value);
|
||||
}
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
|
||||
int16_t i;
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
if(strcmp(xml->attributeNames[i], name) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool xmlIsWhitespace(char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
#define XML_PARSING_CHILD 0x07
|
||||
#define XML_PARSING_CLOSE 0x08
|
||||
|
||||
#define XML_TEXT_BUFFER_MAX 256
|
||||
#define XML_TEXT_BUFFER_MAX 2048
|
||||
#define XML_CHILD_COUNT_MAX 128
|
||||
#define XML_ATTRIBUTE_MAX 128
|
||||
|
||||
|
6
src/dawntools/visualnovel/CMakeLists.txt
Normal file
6
src/dawntools/visualnovel/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Copyright (c) 2023 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(vnscenegen)
|
22
src/dawntools/visualnovel/vnscenegen/CMakeLists.txt
Normal file
22
src/dawntools/visualnovel/vnscenegen/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2023 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Texture Build Tool
|
||||
project(vnscenegen VERSION 1.0)
|
||||
add_executable(vnscenegen)
|
||||
target_sources(vnscenegen
|
||||
PRIVATE
|
||||
main.cpp
|
||||
../../utils/file.c
|
||||
)
|
||||
target_include_directories(vnscenegen
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_libraries(vnscenegen
|
||||
PUBLIC
|
||||
${DAWN_BUILD_HOST_LIBS}
|
||||
)
|
15
src/dawntools/visualnovel/vnscenegen/main.cpp
Normal file
15
src/dawntools/visualnovel/vnscenegen/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
extern "C" {
|
||||
#include "../../utils/file.h"
|
||||
#include <memory.h>
|
||||
}
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
int main(int32_t argc, char *args[]) {
|
||||
|
||||
}
|
Reference in New Issue
Block a user