int hashify_write_file(stream_t* generated_file, string_t output_filename) { bool need_update = false; stream_t* output_file = 0; int result = HASHIFY_RESULT_OK; output_file = stream_open(STRING_ARGS(output_filename), STREAM_OUT | STREAM_IN); if (!output_file) { need_update = true; output_file = stream_open(STRING_ARGS(output_filename), STREAM_OUT); if (!output_file) { log_warnf(0, WARNING_INVALID_VALUE, STRING_CONST("Unable to open output file: %.*s"), STRING_FORMAT(output_filename)); return HASHIFY_RESULT_MISSING_OUTPUT_FILE; } } if (!need_update) need_update = !uint128_equal(stream_md5(generated_file), stream_md5(output_file)); if (need_update) { char local_buffer[1024]; size_t read = 0; size_t written = 0; uint64_t total_written = 0; stream_seek(generated_file, 0, STREAM_SEEK_BEGIN); stream_seek(output_file, 0, STREAM_SEEK_BEGIN); while (!stream_eos(generated_file)) { read = stream_read(generated_file, local_buffer, 1024); if (!read) break; written = stream_write(output_file, local_buffer, read); total_written += written; if (written != read) { log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to write to output file '%.*s': %" PRIsize " of %" PRIsize " bytes written"), STRING_FORMAT(output_filename), written, read); result = HASHIFY_RESULT_OUTPUT_FILE_WRITE_FAIL; break; } } if (result == HASHIFY_RESULT_OK) { stream_truncate(output_file, (size_t)total_written); log_infof(0, STRING_CONST(" wrote %.*s : %" PRIu64 " bytes"), STRING_FORMAT(output_filename), total_written); } } else { log_info(0, STRING_CONST(" hash file already up to date")); } stream_deallocate(output_file); return result; }
int Fl_XmlDefaultTokenizer::stream_read(char *buf, int length) { if(!stream_eos()) { int readed = ((Fl_IO*)io_ctx)->read(buf, length); if(readed>0) return readed; } return -1; }
string_t stream_read_line(stream_t* stream, char delimiter) { char buffer[128]; char* outbuffer = 0; size_t outsize = 0; size_t cursize = 0; size_t read, i; size_t want_read = 128; if (!(stream->mode & STREAM_IN)) return (string_t) { 0, 0 }; //Need to read one byte at a time since we can't scan back if overreading if (stream_is_sequential(stream)) want_read = 1; while (!stream_eos(stream)) { read = stream->vtable->read(stream, buffer, want_read); if (!read) break; for (i = 0; i < read; ++i) { if (buffer[i] == delimiter) break; } if (cursize + i > outsize) { size_t nextsize; if (!outbuffer) { nextsize = (i >= 32 ? i + 1 : (i > 1 ? i + 1 : 32)); outbuffer = memory_allocate(0, nextsize, 0, MEMORY_PERSISTENT); } else { nextsize = (outsize < 511 ? 512 : outsize + 513); //Always aligns to 512 multiples FOUNDATION_ASSERT(!(nextsize % 512)); outbuffer = memory_reallocate(outbuffer, nextsize, 0, outsize + 1); } outsize = nextsize - 1; } if (i) { memcpy(outbuffer + cursize, buffer, i); //lint !e613 cursize += i; } if (i < read) { if ((i + 1) < read) { //Sequential should never end up here reading one byte at a time FOUNDATION_ASSERT(!stream_is_sequential(stream)); stream_seek(stream, (ssize_t)(1 + i) - (ssize_t)read, STREAM_SEEK_CURRENT); } break; } } if (outbuffer) outbuffer[cursize] = 0; return (string_t) { outbuffer, cursize }; }
char* stream_read_line( stream_t* stream, char delimiter ) { char buffer[128]; char* outbuffer; int outsize = 32; int cursize = 0; int read, i; int want_read = 128; FOUNDATION_ASSERT( stream ); if( !( stream->mode & STREAM_IN ) ) return 0; FOUNDATION_ASSERT( stream->vtable->read ); if( stream_is_sequential( stream ) ) //Need to read one byte at a time since we can't scan back if overreading want_read = 1; outbuffer = memory_allocate( outsize + 1, 0, MEMORY_PERSISTENT ); while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, buffer, want_read ); if( !read ) break; for( i = 0; i < read; ++i ) { if( buffer[i] == delimiter ) break; } if( cursize + i > outsize ) { outsize += 512; outbuffer = memory_reallocate( outbuffer, outsize + 1, 0, cursize ); } memcpy( outbuffer + cursize, buffer, i ); cursize += i; if( i < read ) { if( ( i + 1 ) < read ) { FOUNDATION_ASSERT( !stream_is_sequential( stream ) ); //Sequential should never end up here reading one byte at a time stream_seek( stream, 1 + i - read, STREAM_SEEK_CURRENT ); } break; } } outbuffer[cursize] = 0; return outbuffer; }
uint64_t stream_read_line_buffer( stream_t* stream, char* dest, unsigned int count, char delimiter ) { int i, read, total, limit; FOUNDATION_ASSERT( stream ); FOUNDATION_ASSERT( dest ); if( !( stream->mode & STREAM_IN ) || ( count < 2 ) ) return 0; FOUNDATION_ASSERT( stream->vtable->read ); total = 0; --count; while( !stream_eos( stream ) ) { limit = count - total; if( limit > 128 ) limit = 128; if( !limit ) break; if( stream_is_sequential( stream ) ) //Need to read one byte at a time since we can't scan back if overreading limit = 1; read = (int)stream->vtable->read( stream, dest + total, limit ); if( !read ) break; for( i = 0; i < read; ++i ) { if( dest[total+i] == delimiter ) break; } total += i; if( i < read ) { if( ( i + 1 ) < read ) { FOUNDATION_ASSERT( !stream_is_sequential( stream ) ); //Sequential should never end up here reading one byte at a time stream_seek( stream, 1 + i - read, STREAM_SEEK_CURRENT ); } break; } } dest[total] = 0; return total; }
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; }
string_t stream_read_line_buffer(stream_t* stream, char* dest, size_t count, char delimiter) { size_t i, read, total, limit, hardlimit; if (!(stream->mode & STREAM_IN) || !dest || (count < 2)) { if (dest && count) dest[0] = 0; return (string_t) { dest, 0 }; } total = 0; hardlimit = stream_is_sequential(stream) ? 1 : 128; //Need to read one byte at a time since we can't scan back if overreading in sequential streams --count; while (!stream_eos(stream)) { limit = count - total; if (limit > hardlimit) limit = hardlimit; if (!limit) break; //This will initialize range [total,total+read) in dest array, making //access of potentially uninitialized dest array safe (see coverity markup below) read = stream->vtable->read(stream, dest + total, limit); if (!read) break; for (i = 0; i < read; ++i) { /* coverity[read_parm] */ if (dest[total + i] == delimiter) break; } total += i; if (i < read) { if ((i + 1) < read) { //Sequential should never end up here reading one byte at a time FOUNDATION_ASSERT(!stream_is_sequential(stream)); stream_seek(stream, (ssize_t)(1 + i) - (ssize_t)read, STREAM_SEEK_CURRENT); } break; } } dest[total] = 0; return (string_t) { dest, total }; }
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 bin2hex_process_file( stream_t* input, stream_t* output, int columns ) { uint8_t block[512]; int64_t read, byte; if( !columns ) columns = 32; if( columns > 512 ) columns = 512; while( !stream_eos( input ) ) { read = stream_read( input, block, columns ); if( !read ) break; for( byte = 0; byte < read; ++byte ) stream_write_format( output, "0x%02x, ", (unsigned int)block[byte] ); stream_write_endl( output ); } return BIN2HEX_RESULT_OK; }
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_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; }
uint128_t stream_md5( stream_t* stream ) { int64_t cur, ic, offset, lastc, num; md5_t* md5; uint128_t ret = {0}; unsigned char buf[1025]; bool ignore_lf = false; FOUNDATION_ASSERT( stream ); if( stream->vtable->md5 ) return stream->vtable->md5( stream ); if( !stream || stream_is_sequential( stream ) || !( stream->mode & STREAM_IN ) ) return ret; FOUNDATION_ASSERT( stream->vtable->read ); cur = stream_tell( stream ); stream_seek( stream, 0, STREAM_SEEK_BEGIN ); md5 = md5_allocate(); while( !stream_eos( stream ) ) { num = (int64_t)stream->vtable->read( stream, buf, 1024 ); if( !num ) continue; if( stream->mode & STREAM_BINARY ) md5_digest_raw( md5, buf, (size_t)num ); else { //If last buffer ended with CR, ignore a leading LF offset = 0; lastc = 0; if( ignore_lf && ( buf[0] == '\n' ) ) offset = 1; ignore_lf = false; //Treat all line endings (LF, CR, CR+LF) as Unix style LF. If file has mixed line endings (for example, one line ending in a single CR and next ending in a single LF), it will not work! for( ic = 0; ic < num; ++ic ) { bool was_cr = ( buf[ic] == '\r' ); bool was_lf = ( buf[ic] == '\n' ); if( was_cr || was_lf ) { if( was_cr && ( ic >= 1023 ) ) ignore_lf = true; buf[ic] = '\n'; md5_digest_raw( md5, buf + lastc, (size_t)( ic - lastc + 1 ) ); //Include the LF if( was_cr && ( buf[ic+1] == '\n' ) ) //Check for CR+LF ++ic; lastc = ic + 1; } } if( lastc < num ) md5_digest_raw( md5, buf + lastc, (size_t)( num - lastc ) ); } } stream_seek( stream, cur, STREAM_SEEK_BEGIN ); md5_finalize( md5 ); ret = md5_get_digest_raw( md5 ); md5_deallocate( md5 ); return ret; }
uint64_t stream_read_string_buffer( stream_t* stream, char* outbuffer, uint64_t size ) { char buffer[128]; int cursize = 0; int read, i; bool binary = stream_is_binary( stream ); FOUNDATION_ASSERT( stream ); if( !( stream->mode & STREAM_IN ) || !size ) return 0; FOUNDATION_ASSERT( stream->vtable->read ); --size; //TODO: Implement per-byte reading for sequential streams if( !binary ) { //Consume whitespace while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, buffer, 16 ); if( !read ) break; for( i = 0; i < read; ++i ) { char c = buffer[i]; if( ( c != ' ' ) && ( c != '\n' ) && ( c != '\r' ) && ( c != '\t' ) ) break; } if( i < read ) { stream_seek( stream, i - read, STREAM_SEEK_CURRENT ); break; } } } while( !stream_eos( stream ) && ( cursize < (int)size ) ) { read = (int)stream->vtable->read( stream, buffer, 128 ); if( !read ) break; for( i = 0; i < read; ++i ) { char c = buffer[i]; if( !c ) break; if( !binary && ( ( c == ' ' ) || ( c == '\n' ) || ( c == '\r' ) || ( c == '\t' ) ) ) break; } if( !i ) break; if( cursize + i > (int)size ) i = (int)size - cursize; memcpy( outbuffer + cursize, buffer, i ); cursize += i; if( i < 128 ) { if( ( i + 1 ) < read ) stream_seek( stream, 1 + i - read, STREAM_SEEK_CURRENT ); break; } } outbuffer[cursize] = 0; return cursize; }
char* stream_read_string( stream_t* stream ) { char buffer[128]; char* outbuffer; int outsize = 128; int cursize = 0; int read, i; bool binary = stream_is_binary( stream ); FOUNDATION_ASSERT( stream ); if( !( stream->mode & STREAM_IN ) ) return 0; FOUNDATION_ASSERT( stream->vtable->read ); outbuffer = memory_allocate( outsize, 0, MEMORY_PERSISTENT ); if( stream_is_sequential( stream ) ) { //Single byte reading since we can't seek backwards (and don't want to block on network sockets) char c; if( !binary ) { //Consume whitespace while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, &c, 1 ); if( !read ) break; if( ( c != ' ' ) && ( c != '\n' ) && ( c != '\r' ) && ( c != '\t' ) ) { outbuffer[cursize++] = c; break; } } } while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, &c, 1 ); if( !read ) break; if( !c ) break; if( !binary && ( ( c == ' ' ) || ( c == '\n' ) || ( c == '\r' ) || ( c == '\t' ) ) ) break; if( cursize + 1 > outsize ) { outsize += 512; outbuffer = memory_reallocate( outbuffer, outsize, 0, cursize ); } outbuffer[cursize++] = c; } outbuffer[cursize] = 0; } else { if( !binary ) { //Consume whitespace while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, buffer, 16 ); if( !read ) break; for( i = 0; i < read; ++i ) { char c = buffer[i]; if( ( c != ' ' ) && ( c != '\n' ) && ( c != '\r' ) && ( c != '\t' ) ) break; } if( i < read ) { stream_seek( stream, i - read, STREAM_SEEK_CURRENT ); break; } } } while( !stream_eos( stream ) ) { read = (int)stream->vtable->read( stream, buffer, 128 ); if( !read ) break; for( i = 0; i < read; ++i ) { char c = buffer[i]; if( !c ) break; if( !binary && ( ( c == ' ' ) || ( c == '\n' ) || ( c == '\r' ) || ( c == '\t' ) ) ) break; } if( i ) { if( cursize + i > outsize ) { outsize += 512; outbuffer = memory_reallocate( outbuffer, outsize, 0, cursize ); } memcpy( outbuffer + cursize, buffer, i ); cursize += i; } if( i < 128 ) { if( ( i + 1 ) < read ) stream_seek( stream, 1 + i - read, STREAM_SEEK_CURRENT ); break; } } outbuffer[cursize] = 0; } return outbuffer; }
string_t stream_read_string(stream_t* stream) { char buffer[128]; char* outbuffer = buffer; size_t outsize = sizeof(buffer); size_t cursize = 0; size_t read, i; bool binary = stream_is_binary(stream); if (!(stream->mode & STREAM_IN)) return (string_t) { 0, 0 }; if (stream_is_sequential(stream)) { //Single byte reading since we can't seek backwards (and don't want to block on network sockets) char c; if (!binary) { //Consume whitespace while (!stream_eos(stream)) { read = stream->vtable->read(stream, &c, 1); if (!read) break; if ((c != ' ') && (c != '\n') && (c != '\r') && (c != '\t')) { buffer[cursize++] = c; break; } } } if (cursize > 0) { while (!stream_eos(stream)) { read = stream->vtable->read(stream, &c, 1); if (!read) break; if (!c) break; if (!binary && ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) break; if (cursize + 1 >= outsize) { outsize += 512; if (outbuffer != buffer) { outbuffer = memory_reallocate(outbuffer, outsize, 0, cursize); } else { outbuffer = memory_allocate(0, outsize, 0, MEMORY_PERSISTENT); memcpy(outbuffer, buffer, sizeof(buffer)); } } outbuffer[cursize++] = c; } outbuffer[cursize] = 0; //lint !e661 } } else { if (!binary) { //Consume whitespace while (!stream_eos(stream)) { read = stream->vtable->read(stream, buffer, 16); if (!read) break; for (i = 0; i < read; ++i) { char c = buffer[i]; if ((c != ' ') && (c != '\n') && (c != '\r') && (c != '\t')) break; } if (i < read) { stream_seek(stream, (ssize_t)i - (ssize_t)read, STREAM_SEEK_CURRENT); break; } } } while (!stream_eos(stream)) { if (outbuffer != buffer) read = stream->vtable->read(stream, buffer, sizeof(buffer)); else read = stream->vtable->read(stream, buffer + cursize, sizeof(buffer) - cursize); if (!read) break; for (i = 0; i < read; ++i) { char c = buffer[i]; if (!c) break; if (!binary && ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) break; } if (i) { if (cursize + i >= outsize) { outsize += 512; if (outbuffer != buffer) { outbuffer = memory_reallocate(outbuffer, outsize, 0, cursize); } else { FOUNDATION_ASSERT(cursize == 0); //Or internal assumptions about code flow is incorrect outbuffer = memory_allocate(0, outsize, 0, MEMORY_PERSISTENT); memcpy(outbuffer, buffer, i); } } else if (outbuffer != buffer) memcpy(outbuffer + cursize, buffer, i); cursize += i; } if (i < sizeof(buffer)) { if ((i + 1) < read) stream_seek(stream, (ssize_t)(1 + i) - (ssize_t)read, STREAM_SEEK_CURRENT); break; } } outbuffer[cursize] = 0; } if (outbuffer == buffer) { if (cursize == 0) return (string_t) { 0, 0 }; outbuffer = memory_allocate(0, cursize + 1, 0, MEMORY_PERSISTENT); memcpy(outbuffer, buffer, cursize); outbuffer[cursize] = 0; } return (string_t) { outbuffer, cursize }; }
uint128_t stream_md5(stream_t* stream) { size_t cur, ic, lastc, num, limit; md5_t md5; uint128_t ret = uint128_null(); unsigned char buf[1025]; bool ignore_lf = false; if (stream->vtable->md5) return stream->vtable->md5(stream); if (stream_is_sequential(stream) || !(stream->mode & STREAM_IN)) return ret; cur = stream_tell(stream); stream_seek(stream, 0, STREAM_SEEK_BEGIN); md5_initialize(&md5); limit = sizeof(buf)-1; buf[limit] = 0; while (!stream_eos(stream)) { num = stream->vtable->read(stream, buf, limit); if (!num) continue; if (stream->mode & STREAM_BINARY) md5_digest(&md5, buf, (size_t)num); else { //If last buffer ended with CR, ignore a leading LF lastc = 0; if (ignore_lf && (buf[0] == '\n')) lastc = 1; ignore_lf = false; //Digest one line at a time //Treat all line endings (LF, CR, CR+LF) as Unix style LF. If file has mixed line endings //(for example, one line ending in a single CR and next is empty and ending in a single LF), //it will not work! /*lint -e{850} */ for (ic = lastc; ic < num && ic < limit; ++ic) { bool was_cr = (buf[ic] == '\r'); bool was_lf = (buf[ic] == '\n'); if (was_cr || was_lf) { if (was_cr && (ic == limit-1)) ignore_lf = true; //Make next buffer ignore leading LF as it is part of CR+LF buf[ic] = '\n'; md5_digest(&md5, buf + lastc, (size_t)((ic - lastc) + 1)); //Include the LF if (was_cr && (buf[ic + 1] == '\n')) //Check for CR+LF ++ic; lastc = ic + 1; } } if (lastc < num) md5_digest(&md5, buf + lastc, (size_t)(num - lastc)); } } stream_seek(stream, (ssize_t)cur, STREAM_SEEK_BEGIN); md5_digest_finalize(&md5); ret = md5_get_digest_raw(&md5); md5_finalize(&md5); return ret; }
unsigned int stacktrace_capture( void** trace, unsigned int max_depth, unsigned int skip_frames ) { unsigned int num_frames = 0; if( !trace ) return 0; if( !max_depth ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH; if( max_depth > BUILD_SIZE_STACKTRACE_DEPTH ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH; if( !_stackwalk_initialized ) { if( !_initialize_stackwalker() ) { memset( trace, 0, sizeof( void* ) * max_depth ); return num_frames; } } #if FOUNDATION_PLATFORM_WINDOWS && ( FOUNDATION_COMPILER_MSVC || FOUNDATION_COMPILER_INTEL ) // Add 1 skip frame for this function call ++skip_frames; # if USE_CAPTURESTACKBACKTRACE if( CallRtlCaptureStackBackTrace ) { void* local_trace[BUILD_SIZE_STACKTRACE_DEPTH]; if( max_depth + skip_frames > BUILD_SIZE_STACKTRACE_DEPTH ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH - skip_frames; num_frames = (unsigned int)CallRtlCaptureStackBackTrace( skip_frames, max_depth, local_trace, 0 ); if( num_frames > max_depth ) num_frames = max_depth; memcpy( trace, local_trace, sizeof( void* ) * num_frames ); memset( trace + num_frames, 0, sizeof( void* ) * ( max_depth - num_frames ) ); } else { # else { # endif # if FOUNDATION_PLATFORM_ARCH_X86_64 // Raise an exception so helper has access to context record. __try { RaiseException( 0, // Application-defined exception code. 0, // Zero indicates continuable exception. 0, // Number of arguments in args array (ignored if args is null) 0 ); // Array of arguments } __except( _capture_stack_trace_helper( trace, max_depth, skip_frames, (GetExceptionInformation())->ContextRecord ) ) { } # else // Use a bit of inline assembly to capture the information relevant to stack walking which is // basically EIP and EBP. CONTEXT context; memset( &context, 0, sizeof( CONTEXT ) ); context.ContextFlags = CONTEXT_FULL; log_warnf( WARNING_DEPRECATED, "********** REIMPLEMENT FALLBACK STACKTRACE **********" ); /* Use a fake function call to pop the return address and retrieve EIP.*/ __asm { call FakeStackTraceCall FakeStackTraceCall: pop eax mov context.Eip, eax mov context.Ebp, ebp mov context.Esp, esp } // Capture the back trace. _capture_stack_trace_helper( trace, max_depth, skip_frames, &context ); # endif } #elif FOUNDATION_PLATFORM_APPLE //TODO: Implement #elif FOUNDATION_PLATFORM_POSIX // Add 1 skip frames for this function call skip_frames += 1; void* localframes[BUILD_SIZE_STACKTRACE_DEPTH]; num_frames = (unsigned int)backtrace( localframes, BUILD_SIZE_STACKTRACE_DEPTH ); if( num_frames > skip_frames ) { num_frames -= skip_frames; if( num_frames > max_depth ) num_frames = max_depth; memcpy( trace, localframes + skip_frames, sizeof( void* ) * num_frames ); } else trace[0] = 0; #endif return num_frames; } static bool _symbol_resolve_initialized = false; static bool _initialize_symbol_resolve() { if( _symbol_resolve_initialized ) return true; #if FOUNDATION_PLATFORM_WINDOWS { unsigned int options; void* dll = LoadLibraryA( "PSAPI.DLL" ); if( !dll ) return _symbol_resolve_initialized; CallEnumProcesses = (EnumProcessesFn)GetProcAddress( dll, "EnumProcesses" ); CallEnumProcessModules = (EnumProcessModulesFn)GetProcAddress( dll, "EnumProcessModules" ); CallGetModuleFileNameEx = (GetModuleFileNameExFn)GetProcAddress( dll, "GetModuleFileNameExA" ); CallGetModuleBaseName = (GetModuleBaseNameFn)GetProcAddress( dll, "GetModuleBaseNameA" ); CallGetModuleInformation = (GetModuleInformationFn)GetProcAddress( dll, "GetModuleInformation" ); if( !CallEnumProcesses || !CallEnumProcessModules || !CallGetModuleFileNameEx || !CallGetModuleBaseName || !CallGetModuleInformation ) return _symbol_resolve_initialized; dll = LoadLibraryA( "DBGHELP.DLL" ); if( !dll ) return _symbol_resolve_initialized; CallSymInitialize = (SymInitializeFn)GetProcAddress( dll, "SymInitialize" ); CallSymSetOptions = (SymSetOptionsFn)GetProcAddress( dll, "SymSetOptions" ); CallSymGetOptions = (SymGetOptionsFn)GetProcAddress( dll, "SymGetOptions" ); CallSymLoadModule64 = (SymLoadModule64Fn)GetProcAddress( dll, "SymLoadModule64" ); CallSymSetSearchPath = (SymSetSearchPathFn)GetProcAddress( dll, "SymSetSearchPath" ); CallSymGetModuleInfo64 = (SymGetModuleInfo64Fn)GetProcAddress( dll, "SymGetModuleInfo64" ); CallSymGetLineFromAddr64 = (SymGetLineFromAddr64Fn)GetProcAddress( dll, "SymGetLineFromAddr64" ); CallSymGetSymFromAddr64 = (SymGetSymFromAddr64Fn)GetProcAddress( dll, "SymGetSymFromAddr64" ); CallSymGetModuleBase64 = (SymGetModuleBase64Fn)GetProcAddress( dll, "SymGetModuleBase64" ); CallSymFunctionTableAccess64 = (SymFunctionTableAccess64Fn)GetProcAddress( dll, "SymFunctionTableAccess64" ); if( !CallSymInitialize || !CallSymSetOptions || !CallSymGetOptions || !CallSymLoadModule64 || !CallSymSetSearchPath || !CallSymGetModuleInfo64 || !CallSymGetLineFromAddr64 || !CallSymGetSymFromAddr64 || !CallSymGetModuleBase64 || !CallSymFunctionTableAccess64 ) return _symbol_resolve_initialized; options = CallSymGetOptions(); options |= SYMOPT_LOAD_LINES; options |= SYMOPT_DEBUG; options |= SYMOPT_UNDNAME; options |= SYMOPT_LOAD_LINES; options |= SYMOPT_FAIL_CRITICAL_ERRORS; options |= SYMOPT_DEFERRED_LOADS; options |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS; options |= SYMOPT_EXACT_SYMBOLS; options |= SYMOPT_CASE_INSENSITIVE; CallSymSetOptions( options ); CallSymInitialize( GetCurrentProcess(), 0, TRUE ); } _load_process_modules(); _symbol_resolve_initialized = true; #else _symbol_resolve_initialized = true; #endif return _symbol_resolve_initialized; } static NOINLINE char** _resolve_stack_frames( void** frames, unsigned int max_frames ) { #if FOUNDATION_PLATFORM_WINDOWS char** lines = 0; char symbol_buffer[ sizeof( IMAGEHLP_SYMBOL64 ) + 512 ]; PIMAGEHLP_SYMBOL64 symbol; DWORD displacement = 0; uint64_t displacement64 = 0; unsigned int iaddr = 0; unsigned int last_error; bool found = false; HANDLE process_handle = GetCurrentProcess(); int buffer_offset = 0; bool last_was_main = false; IMAGEHLP_LINE64 line64; IMAGEHLP_MODULE64 module64; for( iaddr = 0; ( iaddr < max_frames ) && !last_was_main; ++iaddr ) { char* resolved = 0; const char* function_name = "??"; const char* file_name = "??"; const char* module_name = "??"; unsigned int line_number = 0; //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; // Initialize symbol. symbol = (PIMAGEHLP_SYMBOL64)symbol_buffer; memset( symbol, 0, sizeof( symbol_buffer ) ); symbol->SizeOfStruct = sizeof( symbol_buffer ); symbol->MaxNameLength = 512; // Get symbol from address. if( CallSymGetSymFromAddr64 && CallSymGetSymFromAddr64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &displacement64, symbol ) ) { int offset = 0; while( symbol->Name[offset] < 32 ) ++offset; function_name = symbol->Name + offset; } else { // No symbol found for this address. last_error = GetLastError(); } memset( &line64, 0, sizeof( line64 ) ); line64.SizeOfStruct = sizeof( line64 ); if( CallSymGetLineFromAddr64 && CallSymGetLineFromAddr64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &displacement, &line64 ) ) { file_name = line64.FileName; line_number = line64.LineNumber; } memset( &module64, 0, sizeof( module64 ) ); module64.SizeOfStruct = sizeof( module64 ); if( CallSymGetModuleInfo64 && CallSymGetModuleInfo64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &module64 ) ) { int last_slash = STRING_NPOS; module_name = module64.ImageName; last_slash = string_rfind( module_name, '\\', STRING_NPOS ); if( last_slash != STRING_NPOS ) module_name += last_slash + 1; } resolved = string_format( "[" STRING_FORMAT_POINTER "] %s (%s:%d +%d bytes) [in %s]", frames[iaddr], function_name, file_name, line_number, displacement, module_name ); array_push( lines, resolved ); if( string_equal( function_name, "main" ) ) last_was_main = true; } return lines; #elif FOUNDATION_PLATFORM_LINUX char** addrs = 0; char** lines = 0; const char** args = 0; process_t* proc = process_allocate(); unsigned int num_frames = 0; unsigned int requested_frames = 0; bool last_was_main = false; if( !string_length( environment_executable_path() ) ) { for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; array_push( lines, string_format( "[" STRING_FORMAT_POINTER "]", frames[iaddr] ) ); } return lines; } array_push( args, "-e" ); array_push( args, environment_executable_path() ); array_push( args, "-f" ); for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; char* addr = string_format( STRING_FORMAT_POINTER, frames[iaddr] ); array_push( addrs, addr ); array_push( args, addr ); ++requested_frames; } process_set_working_directory( proc, environment_initial_working_directory() ); process_set_executable_path( proc, "/usr/bin/addr2line" ); process_set_arguments( proc, args, array_size( args ) ); process_set_flags( proc, PROCESS_ATTACHED | PROCESS_STDSTREAMS ); process_spawn( proc ); stream_t* procout = process_stdout( proc ); while( !stream_eos( procout ) && ( num_frames < requested_frames ) && !last_was_main ) { char* function = stream_read_line( procout, '\n' ); char* filename = stream_read_line( procout, '\n' ); array_push( lines, string_format( "[" STRING_FORMAT_POINTER "] %s (%s)", frames[num_frames], function && string_length( function ) ? function : "??", filename && string_length( filename ) ? filename : "??" ) ); if( string_equal( function, "main" ) ) last_was_main = true; string_deallocate( function ); string_deallocate( filename ); ++num_frames; } process_wait( proc ); process_deallocate( proc ); string_array_deallocate( addrs ); array_deallocate( args ); return lines; #else char** lines = 0; for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; array_push( lines, string_format( "[" STRING_FORMAT_POINTER "]\n", frames[iaddr] ) ); } return lines; #endif }
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 ); }
int hashify_write_file( stream_t* generated_file, const char* output_filename ) { bool need_update = false; stream_t* output_file = 0; int result = HASHIFY_RESULT_OK; output_file = stream_open( output_filename, STREAM_OUT | STREAM_IN ); if( !output_file ) { need_update = true; output_file = stream_open( output_filename, STREAM_OUT ); if( !output_file ) { log_warnf( WARNING_BAD_DATA, "Unable to open output file: %s", output_filename ); return HASHIFY_RESULT_MISSING_OUTPUT_FILE; } } if( !need_update ) need_update = !uint128_equal( stream_md5( generated_file ), stream_md5( output_file ) ); if( need_update ) { char local_buffer[1024]; uint64_t read = 0; uint64_t written = 0; uint64_t total_written = 0; stream_seek( generated_file, 0, STREAM_SEEK_BEGIN ); stream_seek( output_file, 0, STREAM_SEEK_BEGIN ); while( !stream_eos( generated_file ) ) { read = stream_read( generated_file, local_buffer, 1024 ); if( !read ) break; written = stream_write( output_file, local_buffer, read ); total_written += written; if( written != read ) { log_errorf( ERROR_SYSTEM_CALL_FAIL, "Unable to write to output file '%s': %llu of %llu bytes written", output_filename, written, read ); result = HASHIFY_RESULT_OUTPUT_FILE_WRITE_FAIL; break; } } if( result == HASHIFY_RESULT_OK ) { stream_truncate( output_file, total_written ); log_infof( " wrote %s : %llu bytes", output_filename, total_written ); } } else { log_infof( " hash file already up to date" ); } stream_deallocate( output_file ); return result; }
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; }
string_t stream_read_string_buffer(stream_t* stream, char* outbuffer, size_t size) { char buffer[128]; size_t cursize = 0; size_t read, i; bool binary = stream_is_binary(stream); if (!(stream->mode & STREAM_IN) || !outbuffer || !size) { if (outbuffer && size) outbuffer[0] = 0; return (string_t) { outbuffer, 0 }; } --size; if (stream_is_sequential(stream)) { //Single byte reading since we can't seek backwards (and don't want to block on network sockets) char c; if (!binary) { //Consume whitespace while (!stream_eos(stream)) { read = stream->vtable->read(stream, &c, 1); if (!read) break; if ((c != ' ') && (c != '\n') && (c != '\r') && (c != '\t')) { outbuffer[cursize++] = c; break; } } } if (cursize > 0) { while (!stream_eos(stream) && (cursize < size)) { read = stream->vtable->read(stream, &c, 1); if (!read) break; if (!c) break; if (!binary && ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) break; outbuffer[cursize++] = c; } } } else { if (!binary) { //Consume whitespace while (!stream_eos(stream)) { read = stream->vtable->read(stream, buffer, 16); if (!read) break; for (i = 0; i < read; ++i) { char c = buffer[i]; if ((c != ' ') && (c != '\n') && (c != '\r') && (c != '\t')) break; } if (i < read) { stream_seek(stream, (ssize_t)i - (ssize_t)read, STREAM_SEEK_CURRENT); break; } } } while (!stream_eos(stream) && (cursize < size)) { read = stream->vtable->read(stream, buffer, 128); if (!read) break; for (i = 0; i < read; ++i) { char c = buffer[i]; if (!c) break; if (!binary && ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) break; } if (!i) break; if (cursize + i > size) i = size - cursize; memcpy(outbuffer + cursize, buffer, i); cursize += i; if (i < 128) { if ((i + 1) < read) stream_seek(stream, (ssize_t)(1 + i) - (ssize_t)read, STREAM_SEEK_CURRENT); break; } } } if (cursize < size) outbuffer[cursize] = 0; return (string_t) {outbuffer, cursize}; }
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; }