int hashify_generate_preamble(stream_t* output_file, string_t output_filename) { //Read and preserve everything before #pragma once in case it contains header comments to be preserved char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; size_t capacity = 1024; string_t preamble = string_allocate(0, capacity); stream_t* prev_file = stream_open(STRING_ARGS(output_filename), STREAM_IN); memset(line_buffer, 0, sizeof(line_buffer)); while (prev_file && !stream_eos(prev_file)) { string_t line; string_const_t stripped_line; line = stream_read_line_buffer(prev_file, line_buffer, sizeof(line_buffer), '\n'); stripped_line = string_strip(STRING_ARGS(line), STRING_CONST("\n\r")); if ((string_find_string(STRING_ARGS(stripped_line), STRING_CONST("pragma"), 0) != STRING_NPOS) && (string_find_string(STRING_ARGS(stripped_line), STRING_CONST("once"), 0) != STRING_NPOS)) break; if (preamble.length + stripped_line.length + 1 >= capacity) { size_t newcapacity = capacity + 1024 + stripped_line.length; preamble.str = memory_reallocate(preamble.str, newcapacity, 0, capacity); capacity = newcapacity; } preamble = string_append(STRING_ARGS(preamble), capacity, STRING_ARGS(stripped_line)); if (line.length < sizeof(line_buffer)) preamble = string_append(STRING_ARGS(preamble), capacity, STRING_CONST(STRING_NEWLINE)); } stream_deallocate(prev_file); stream_seek(output_file, 0, STREAM_SEEK_BEGIN); if (preamble.length) stream_write_string(output_file, STRING_ARGS(preamble)); stream_write_string(output_file, STRING_CONST( "#pragma once\n\n" "#include <foundation/hash.h>\n\n" "/* ****** AUTOMATICALLY GENERATED, DO NOT EDIT ******\n" " Edit corresponding definitions file and rerun\n" " the foundation hashify tool to update this file */\n\n" )); string_deallocate(preamble.str); return 0; }
static renderimport_type_t render_import_shader_guess_type(stream_t* stream) { renderimport_type_t type = IMPORTTYPE_UNKNOWN; char buffer[1024]; while (!stream_eos(stream)) { string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n'); if (string_find_string(STRING_ARGS(line), STRING_CONST("gl_FragColor"), 0) != STRING_NPOS) { type = IMPORTTYPE_GLSL_PIXELSHADER; break; } else if (string_find_string(STRING_ARGS(line), STRING_CONST("gl_Position"), 0) != STRING_NPOS) { type = IMPORTTYPE_GLSL_VERTEXSHADER; break; } } stream_seek(stream, 0, STREAM_SEEK_BEGIN); return type; }
int hashify_read_hashes(stream_t* file, hashify_string_t** hashes) { //Read in hashes in file char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; string_const_t tokens[32]; memset(line_buffer, 0, sizeof(line_buffer)); do { string_t line = stream_read_line_buffer(file, line_buffer, sizeof(line_buffer), '\n'); string_const_t stripped_line = string_strip(STRING_ARGS(line), STRING_CONST("\n\r")); if ((string_find_string(STRING_ARGS(stripped_line), STRING_CONST("define"), 0) != STRING_NPOS) && (string_find_string(STRING_ARGS(stripped_line), STRING_CONST("static_hash"), 0) != STRING_NPOS)) { //Format is: #define HASH_<hashstring> static_hash_string( "<string>", 0x<hashvalue>ULL ) size_t num_tokens = string_explode(STRING_ARGS(stripped_line), STRING_CONST(" \t"), tokens, 32, false); if (num_tokens >= 6) { hashify_string_t hash_string; string_const_t stripped = string_strip(STRING_ARGS(tokens[3]), STRING_CONST(",")); stripped = string_strip(STRING_ARGS(stripped), STRING_CONST("\"")); hash_string.string = string_copy(hash_string.buffer, HASHIFY_STRING_LENGTH, STRING_ARGS(stripped)); hash_string.hash = string_to_uint64(STRING_ARGS(tokens[4]), true); if (hash(STRING_ARGS(hash_string.string)) != hash_string.hash) { log_errorf(0, ERROR_INVALID_VALUE, STRING_CONST(" hash output file is out of date, %.*s is set to 0x%" PRIx64 " but should be 0x%" PRIx64), STRING_FORMAT(hash_string.string), hash_string.hash, hash(STRING_ARGS(hash_string.string))); return HASHIFY_RESULT_OUTPUT_FILE_OUT_OF_DATE; } array_push_memcpy(*hashes, &hash_string); } } } while (!stream_eos(file)); return 0; }
int hashify_read_hashes( stream_t* file, hashify_string_t** hashes ) { //Read in hashes in file char* line; char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; do { stream_read_line_buffer( file, line_buffer, HASHIFY_LINEBUFFER_LENGTH-1, '\n' ); line = string_strip( line_buffer, "\n\r" ); if( ( string_find_string( line, "define", 0 ) != STRING_NPOS ) && ( string_find_string( line, "static_hash", 0 ) != STRING_NPOS ) ) { //Format is: #define HASH_<hashstring> static_hash_string( "<string>", 0x<hashvalue>ULL ) char** tokens = string_explode( line, " \t", false ); if( array_size( tokens ) >= 6 ) { hashify_string_t hash_string; string_copy( hash_string.string, string_strip( string_strip( tokens[3], "," ), "\"" ), HASHIFY_STRING_LENGTH ); hash_string.hash = string_to_uint64( tokens[4], true ); if( hash( hash_string.string, string_length( hash_string.string ) ) != hash_string.hash ) { log_errorf( ERROR_INVALID_VALUE, " hash output file is out of date, %s is set to 0x%llx but should be 0x%llx ", hash_string.string, hash_string.hash, hash( hash_string.string, string_length( hash_string.string ) ) ); string_array_deallocate( tokens ); return HASHIFY_RESULT_OUTPUT_FILE_OUT_OF_DATE; } array_push_memcpy( *hashes, &hash_string ); } string_array_deallocate( tokens ); } } while( !stream_eos( file ) ); return 0; }
int hashify_generate_preamble( stream_t* output_file ) { //Read and preserve everything before #pragma once in case it contains header comments to be preserved char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; char* preamble = 0; while( !stream_eos( output_file ) ) { char* line; uint64_t read; read = stream_read_line_buffer( output_file, line_buffer, HASHIFY_LINEBUFFER_LENGTH-1, '\n' ); line = string_strip( line_buffer, "\n\r" ); if( ( string_find_string( line, "pragma", 0 ) != STRING_NPOS ) && ( string_find_string( line, "once", 0 ) != STRING_NPOS ) ) break; preamble = string_append( preamble, line ); if( read < HASHIFY_LINEBUFFER_LENGTH ) preamble = string_append( preamble, "\n" ); } stream_seek( output_file, 0, STREAM_SEEK_BEGIN ); stream_write_string( output_file, preamble ); stream_write_string( output_file, "#pragma once\n\n" "#include <foundation/foundation.h>\n\n" "/* ****** AUTOMATICALLY GENERATED, DO NOT EDIT ******\n" " Edit corresponding definitions file and rerun\n" " the foundation hashify tool to update this file */\n\n" ); string_deallocate( preamble ); return 0; }
static int render_import_program(stream_t* stream, const uuid_t uuid) { char buffer[1024]; char pathbuf[BUILD_MAX_PATHLEN]; resource_source_t source; resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1}; uint64_t platform; tick_t timestamp; int ret = 0; resource_source_initialize(&source); resource_source_read(&source, uuid); platform = resource_platform(platformdecl); timestamp = time_system(); while (!stream_eos(stream)) { string_const_t type, ref; string_const_t fullpath; string_const_t uuidstr; uuid_t shaderuuid; hash_t typehash; string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n'); string_split(STRING_ARGS(line), STRING_CONST(" \t"), &type, &ref, false); type = string_strip(STRING_ARGS(type), STRING_CONST(STRING_WHITESPACE)); ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE)); if (!type.length || !ref.length) continue; typehash = hash(STRING_ARGS(type)); if ((typehash != HASH_VERTEXSHADER) && (typehash != HASH_PIXELSHADER)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Ignore invalid line: %.*s"), STRING_FORMAT(line)); continue; } shaderuuid = string_to_uuid(STRING_ARGS(ref)); if (uuid_is_null(shaderuuid)) { if (path_is_absolute(STRING_ARGS(ref))) { fullpath = ref; } else { string_t full; string_const_t path = stream_path(stream); path = path_directory_name(STRING_ARGS(path)); full = path_concat(pathbuf, sizeof(pathbuf), STRING_ARGS(path), STRING_ARGS(ref)); full = path_absolute(STRING_ARGS(full), sizeof(pathbuf)); fullpath = string_const(STRING_ARGS(full)); } resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { if (!resource_import(STRING_ARGS(fullpath), uuid_null())) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Unable to import linked shader: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Import linked shader gave no UUID: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } } shaderuuid = sig.uuid; } if (!uuid_is_null(shaderuuid)) { uuidstr = string_from_uuid_static(shaderuuid); resource_source_set(&source, timestamp, typehash, platform, STRING_ARGS(uuidstr)); } } resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, STRING_CONST("program")); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported program: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported program: %.*s"), STRING_FORMAT(uuidstr)); } finalize: resource_source_finalize(&source); return ret; }
static int render_import_shader(stream_t* stream, const uuid_t uuid) { char buffer[1024]; char pathbuf[BUILD_MAX_PATHLEN]; resource_source_t source; resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1}; uint64_t platform; tick_t timestamp; int ret = 0; resource_source_initialize(&source); resource_source_read(&source, uuid); platform = resource_platform(platformdecl); timestamp = time_system(); while (!stream_eos(stream)) { uuid_t shaderuuid; string_const_t target, ref, fullpath; string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n'); string_split(STRING_ARGS(line), STRING_CONST(" \t"), &target, &ref, false); ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE)); shaderuuid = string_to_uuid(STRING_ARGS(ref)); if (uuid_is_null(shaderuuid)) { if (path_is_absolute(STRING_ARGS(ref))) { fullpath = ref; } else { string_t full; string_const_t path = stream_path(stream); path = path_directory_name(STRING_ARGS(path)); full = path_concat(pathbuf, sizeof(pathbuf), STRING_ARGS(path), STRING_ARGS(ref)); full = path_absolute(STRING_ARGS(full), sizeof(pathbuf)); fullpath = string_const(STRING_ARGS(full)); } resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { if (!resource_import(STRING_ARGS(fullpath), uuid_null())) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Unable to import linked shader: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Import linked shader gave no UUID: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } } shaderuuid = sig.uuid; } if (!uuid_is_null(shaderuuid)) { resource_platform_t targetplatformdecl = render_import_parse_target(STRING_ARGS(target), platformdecl); uint64_t targetplatform = resource_platform(targetplatformdecl); if (resource_autoimport_need_update(shaderuuid, targetplatform)) resource_autoimport(shaderuuid); const string_const_t uuidstr = string_from_uuid_static(shaderuuid); resource_source_set(&source, timestamp, HASH_SHADER, targetplatform, STRING_ARGS(uuidstr)); resource_source_set_dependencies(uuid, targetplatform, &shaderuuid, 1); } } resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, STRING_CONST("shader")); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported shader: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported shader: %.*s"), STRING_FORMAT(uuidstr)); } finalize: resource_source_finalize(&source); return 0; }
int hashify_process_file(stream_t* input_file, stream_t* output_file, string_t output_filename, bool check_only, hashify_string_t** history) { int result = HASHIFY_RESULT_OK; char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; hashify_string_t* local_hashes = 0; hashify_string_t* local_generated = 0; if (check_only) result = hashify_read_hashes(output_file, &local_hashes); else result = hashify_generate_preamble(output_file, output_filename); memset(line_buffer, 0, sizeof(line_buffer)); while (!stream_eos(input_file) && (result == HASHIFY_RESULT_OK)) { string_t line_string; string_const_t def_string; string_const_t value_string; line_string = stream_read_line_buffer(input_file, line_buffer, sizeof(line_buffer), '\n'); string_split(STRING_ARGS(line_string), STRING_CONST(" \t"), &def_string, &value_string, false); def_string = string_strip(STRING_ARGS(def_string), STRING_CONST(STRING_WHITESPACE)); value_string = string_strip(STRING_ARGS(value_string), STRING_CONST(STRING_WHITESPACE)); if (value_string.length && (value_string.str[0] == '"') && (value_string.str[ value_string.length - 1 ] == '"')) { ++value_string.str; value_string.length -= 2; } if (def_string.length) { hash_t hash_value = hash(STRING_ARGS(value_string)); log_infof(0, STRING_CONST(" %.*s: %.*s -> 0x%" PRIx64), STRING_FORMAT(def_string), STRING_FORMAT(value_string), hash_value); if (check_only) { //Check local consistency result = hashify_check_local_consistency(value_string, hash_value, local_hashes); } else { stream_write_format(output_file, STRING_CONST("#define %.*s static_hash_string(\"%.*s\", %" PRIsize ", 0x%" PRIx64 "ULL)\n"), STRING_FORMAT(def_string), STRING_FORMAT(value_string), value_string.length, hash_value); } if (result == HASHIFY_RESULT_OK) { hashify_string_t hash_string; //Check history result = hashify_check_collisions(value_string, hash_value, *history); //Add to history hash_string.string = string_copy(hash_string.buffer, HASHIFY_STRING_LENGTH, STRING_ARGS(value_string)); hash_string.hash = hash_value; array_push_memcpy(*history, &hash_string); array_push_memcpy(local_generated, &hash_string); } } } if (check_only) { //Check local consistency result = hashify_check_match(local_hashes, local_generated); } array_deallocate(local_hashes); array_deallocate(local_generated); return result; }
int hashify_process_file( stream_t* input_file, stream_t* output_file, bool check_only, hashify_string_t** history ) { int result = HASHIFY_RESULT_OK; char line_buffer[HASHIFY_LINEBUFFER_LENGTH]; hashify_string_t* local_hashes = 0; hashify_string_t* local_generated = 0; if( check_only ) result = hashify_read_hashes( output_file, &local_hashes ); else result = hashify_generate_preamble( output_file ); while( !stream_eos( input_file ) && ( result == HASHIFY_RESULT_OK ) ) { char* def_string = 0; char* value_string = 0; stream_read_line_buffer( input_file, line_buffer, HASHIFY_LINEBUFFER_LENGTH, '\n' ); string_split( line_buffer, " \t", &def_string, &value_string, false ); string_strip( def_string, STRING_WHITESPACE ); string_strip( value_string, STRING_WHITESPACE ); if( string_length( value_string ) && ( value_string[0] == '"' ) && ( value_string[ string_length( value_string ) - 1 ] == '"' ) ) { unsigned int len = string_length( value_string ); memmove( value_string, value_string + 1, len - 2 ); value_string[len-2] = 0; } if( string_length( def_string ) ) { hash_t hash_value = hash( value_string, string_length( value_string ) ); log_infof( " %s: %s -> 0x%llx", def_string, value_string, hash_value ); if( check_only ) { //Check local consistency result = hashify_check_local_consistency( value_string, hash_value, local_hashes ); } else { stream_write_format( output_file, "#define %s static_hash_string( \"%s\", 0x%llxULL )\n", def_string, value_string, hash_value ); } if( result == HASHIFY_RESULT_OK ) { hashify_string_t hash_string; //Check history result = hashify_check_collisions( value_string, hash_value, *history ); //Add to history string_copy( hash_string.string, value_string, HASHIFY_STRING_LENGTH ); hash_string.hash = hash_value; array_push_memcpy( *history, &hash_string ); array_push_memcpy( local_generated, &hash_string ); } } string_deallocate( def_string ); string_deallocate( value_string ); } if( check_only ) { //Check local consistency result = hashify_check_match( local_hashes, local_generated ); } array_deallocate( local_hashes ); array_deallocate( local_generated ); return result; }
void config_parse( stream_t* stream, hash_t filter_section, bool overwrite ) { char* buffer; hash_t section = 0; hash_t key = 0; unsigned int line = 0; #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, "Parsing config stream: %s", stream_path( stream ) ); #endif buffer = memory_allocate_zero( 1024ULL, 0, MEMORY_TEMPORARY ); while( !stream_eos( stream ) ) { ++line; stream_read_line_buffer( stream, buffer, 1024, '\n' ); string_strip( buffer, " \t\n\r" ); if( !string_length( buffer ) || ( buffer[0] == ';' ) || ( buffer[0] == '#' ) ) continue; if( buffer[0] == '[' ) { //Section declaration unsigned int endpos = string_rfind( buffer, ']', string_length( buffer ) - 1 ); if( ( endpos == STRING_NPOS ) || ( endpos < 1 ) ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid section declaration on line %d in config stream '%s'", line, stream_path( stream ) ); continue; } buffer[endpos] = 0; section = hash( buffer + 1, endpos - 1 ); #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, " config: section set to '%s' (0x%llx)", buffer + 1, section ); #endif } else if( !filter_section || ( filter_section == section ) ) { //name=value declaration char* name; char* value; unsigned int separator = string_find( buffer, '=', 0 ); if( separator == STRING_NPOS ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', missing assignment operator '=': %s", line, stream_path( stream ), buffer ); continue; } name = string_strip_substr( buffer, " \t", separator ); value = string_strip( buffer + separator + 1, " \t" ); if( !string_length( name ) ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', empty name string", line, stream_path( stream ) ); continue; } key = hash( name, string_length( name ) ); if( overwrite || !config_key( section, key, false ) ) { #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, " config: %s (0x%llx) = %s", name, key, value ); #endif if( !string_length( value ) ) config_set_string( section, key, "" ); else if( string_equal( value, "false" ) ) config_set_bool( section, key, false ); else if( string_equal( value, "true" ) ) config_set_bool( section, key, true ); else if( ( string_find( value, '.', 0 ) != STRING_NPOS ) && ( string_find_first_not_of( value, "0123456789.", 0 ) == STRING_NPOS ) && ( string_find( value, '.', string_find( value, '.', 0 ) + 1 ) == STRING_NPOS ) ) //Exactly one "." config_set_real( section, key, string_to_real( value ) ); else if( string_find_first_not_of( value, "0123456789", 0 ) == STRING_NPOS ) config_set_int( section, key, string_to_int64( value ) ); else config_set_string( section, key, value ); } } } memory_deallocate( buffer ); }