// Starts and ends with a " // FIXME: utf8 compatibility // FIXME: escaping characters ExcelValue parseString(char **string) { assert(*string[0] == '"'); // We've started with a " (*string)++; char *start = *string; char currentCharacter; while(true) { currentCharacter = **string; if(currentCharacter == '\0') { return parseFailed("Expected to see a closing \" before reaching the end of the line", start-1); // -1 for opening " } if(currentCharacter == EOF) { return parseFailed("Expected to see a closing \" before reaching the end of the file", start-1); // -1 for opening " } if(currentCharacter == '"') { break; } (*string)++; } int numberOfCharacters = *string - start; (*string)++; // Advance over the closing " char *matchedString = malloc(numberOfCharacters+1); // +1 for closing \0 if(matchedString == 0) { return parseFailed("Out of memory when allocating string", start-1); } memcpy(matchedString, start, numberOfCharacters); matchedString[numberOfCharacters] = '\0'; free_later(matchedString); return EXCEL_STRING(matchedString); }
ExcelValue startArray(char **string) { char *start = *string; // For error reporting (*string)++; // Advance over the [ ExcelValue *array = malloc(ARRAY_ALLOC_SIZE * sizeof(ExcelValue)); if(array == 0) { return parseFailed("Out of memory allocating the array", start); } int length = 0; // The first empty slot in the array int allocatedLength = ARRAY_ALLOC_SIZE; int rows = 0; int columns = 0; char *previousPosition; while(true) { previousPosition = *string; ExcelValue nextExcelValue = parse(string); if(*string == previousPosition) { // We have not made any progress, aborting return parseFailed("Expected to see a closing ] before reaching the end of the file", start); } if(nextExcelValue.type == END_OF_ARRAY.type && nextExcelValue.number == END_OF_ARRAY.number) { if(allocatedLength > length) { // Shrink our memory allocation array = realloc(array, length * sizeof(ExcelValue)); } // Retain the array free_later(array); // Fix the number of rows if(rows == 0 && length > 0) { rows = 1; } // Return the right sort of excel value return EXCEL_RANGE(array,rows, columns); } else if(nextExcelValue.type == ExcelRange) { // If we are here, then we are a multi dimentional array if(nextExcelValue.rows > 1) { return parseFailed("Excel arrays can be, at most 2 dimensional.", start); } if(length > 0 && nextExcelValue.columns != columns) { return parseFailed("Array rows must be identically sized.", start); } // We have a new row rows++; // If the first row, define the number of columns if(length == 0) { columns = nextExcelValue.columns; } // FIXME: Should always have 1 row? int nextValueLength = nextExcelValue.rows * nextExcelValue.columns; // Resize the array if we need to while((length + nextValueLength) > allocatedLength) { array = realloc(array, (allocatedLength + ARRAY_ALLOC_SIZE)*sizeof(ExcelValue)); if(array == 0) { return parseFailed("Out of memory extending the array", start); } allocatedLength = allocatedLength + ARRAY_ALLOC_SIZE; } // Copy over the values memcpy(&array[length], nextExcelValue.array, nextValueLength * sizeof(ExcelValue)); // Update our count length = length + nextValueLength; // Clean up free(nextExcelValue.array); } else { // If we are here, then we are just adding a normal value to the end of a row columns++; // Resize the array if we need to if(length >= allocatedLength) { array = realloc(array, (allocatedLength + ARRAY_ALLOC_SIZE)*sizeof(ExcelValue)); if(array == 0) { return parseFailed("Out of memory extending the array", start); } allocatedLength = allocatedLength + ARRAY_ALLOC_SIZE; } // Then put this element onto the end of the array array[length] = nextExcelValue; // Increment our count length++; } } return parseFailed("Expected to see a closing ] before reaching the end of the file", start); }
virtual void process() { // This happens in the installer thread, so we cannot mess with // anything else. HZIP zip = NULL; try { g_debug( "STARTING INSTALL OF %s", info.source_file.c_str() ); //................................................................. if ( ! verify_and_strip_signatures() ) { throw String( "SIGNATURE CHECK FAILED" ); } //................................................................. // Open the source file to make sure it is ok zip = OpenZip( info.source_file.c_str(), NULL ); if ( ! zip ) { throw String( "FAILED TO OPEN ZIP FILE" ); } ZIPENTRY entry; //................................................................. // Figure out how many items are in the zip file if ( ZR_OK != GetZipItem( zip, -1, &entry ) ) { throw String( "FAILED TO GET ZIP ENTRY COUNT" ); } int entry_count = entry.index; if ( entry_count <= 0 ) { throw String( "ZIP FILE HAS TOO FEW ENTRIES" ); } //................................................................. // Now go through all the items in the zip file, figure out // their total uncompressed size and find the 'app' file. guint64 total_uncompressed_size = 0; String app_file_zip_path; int app_file_zip_index = -1; guint64 app_file_uncompressed_size = 0; for ( int i = 0; i < entry_count; ++i ) { if ( ZR_OK != GetZipItem( zip, i, &entry ) ) { throw String( "FAILED TO GET ZIP ENTRY" ); } total_uncompressed_size += entry.unc_size; // See if this is the app file if ( app_file_zip_path.empty() ) { // THIS IS PLATFORM SPECIFIC if ( ! ( entry.attr & S_IFDIR ) ) { gchar * basename = g_path_get_basename( entry.name ); if ( ! strcmp( basename , "app" ) ) { app_file_zip_path = entry.name; app_file_zip_index = i; app_file_uncompressed_size = entry.unc_size; } g_free( basename ); } } } if ( app_file_zip_path.empty() ) { throw String( "ZIP FILE IS MISSING APP FILE" ); } if ( app_file_uncompressed_size == 0 ) { throw String( "APP FILE UNCOMPRESSED SIZE IS INCORRECT" ); } g_debug( "FOUND APP FILE IN ZIP AT %s", app_file_zip_path.c_str() ); //................................................................. // Uncompress the app file to memory and load its metadata. // We must ensure it is valid and its app_id is the same as the // one passed in. // g_new0 serves to NULL-terminate the contents, which // load_metadata_from_data expects. gchar * app_file_buffer = g_new0( gchar, app_file_uncompressed_size * 2 ); if ( ! app_file_buffer ) { throw String( "FAILED TO ALLOCATE MEMORY TO UNCOMPRESS APP FILE" ); } FreeLater free_later; free_later( app_file_buffer ); if ( ZR_OK != UnzipItem( zip, app_file_zip_index, app_file_buffer, app_file_uncompressed_size * 2 ) ) { throw String( "FAILED TO UNCOMPRESS APP FILE" ); } App::Metadata metadata; if ( ! App::load_metadata_from_data( app_file_buffer, metadata ) ) { throw String( "FAILED TO READ METADATA" ); } if ( metadata.id != info.app_id ) { throw String( "APP ID DOES NOT MATCH" ); } //................................................................. // Figure out where to unzip it to // - should be in the same volume as the app's data directory // // The app may already live in trickplay/apps/<id hash>/source // // We could unzip it to trickplay/apps/installing/<id hash> // The benefit of this is that it would be easy to clean up unfinished // installations by deleting everything in "installing". // // We could unzip it to trickplay/apps/<id hash>/installing // This puts it event closer to its final destination, but we would // have to do more work to clean up. CHOOSING THIS ONE FOR NOW gchar * unzip_path = g_build_filename( info.app_directory.c_str(), "installing", NULL ); free_later( unzip_path ); //................................................................. // If our destination directory already exists, it is probably // from a failed attempt to install this app. We need to get rid of it. if ( g_file_test( unzip_path, G_FILE_TEST_EXISTS ) ) { g_debug( "DELETING OLD INSTALL DIRECTORY %s", unzip_path ); if ( ! recursive_delete_path( unzip_path ) ) { throw String( "FAILED TO DELETE OLD INSTALL DIRECTORY" ); } } if ( 0 != g_mkdir_with_parents( unzip_path, 0700 ) ) { throw String( "FAILED TO CREATE INSTALL DIRECTORY" ); } //................................................................. // TODO: We should now check for free space - and make sure we have at // least total_uncompressed_size available. //................................................................. // OK, everything seems to be in order. // We get the dirname of the path to the app file in the zip. // So, for example, inside the zip, the app file might be in // "foor/bar/app". We have to take all the files in the zip that // are in "foo/bar" and unzip them to our real destination. gchar * app_file_zip_dirname = g_path_get_dirname( app_file_zip_path.c_str() ); g_assert(app_file_zip_dirname); free_later( app_file_zip_dirname ); guint app_file_zip_dirname_length = strlen( app_file_zip_dirname ); // If there is no dirname, the above gets set to "." bool no_zip_root = ! strcmp( app_file_zip_dirname, "." ); // Now, it is time to unzip g_debug( "UNZIPPING TO %s", unzip_path ); guint64 total_processed = 0; Util::GTimer progress_timer; #ifndef TP_PRODUCTION static float slow = -1; if ( slow == -1 ) { if ( const char * e = g_getenv( "TP_INSTALL_DELAY" ) ) { slow = atof( e ); } else { slow = 0; } } #endif for ( int i = 0; i < entry_count; ++i ) { #ifndef TP_PRODUCTION if ( slow ) { usleep( slow * G_USEC_PER_SEC ); } #endif if ( ZR_OK != GetZipItem( zip, i, &entry ) ) { throw String( "FAILED TO GET ZIP ENTRY" ); } gchar * destination_file_name = NULL; if ( no_zip_root ) { destination_file_name = g_build_filename( unzip_path, entry.name, NULL ); } else if ( g_str_has_prefix( entry.name, app_file_zip_dirname ) ) { destination_file_name = g_build_filename( unzip_path, entry.name + app_file_zip_dirname_length, NULL ); } if ( ! destination_file_name ) { g_debug( " SKIPPING %s", entry.name ); } else { free_later( destination_file_name ); g_debug( " UNZIPPING %s", entry.name ); if ( ZR_OK != UnzipItem( zip, i, destination_file_name ) ) { throw String( "FAILED TO UNZIP" ); } } // Report progress total_processed += entry.unc_size; if ( progress_timer.elapsed() >= 1 ) { progress_timer.reset(); info.status = Installer::Info::INSTALLING; info.percent_installed = gdouble( total_processed ) / gdouble( total_uncompressed_size ) * 100.0; send_progress(); } } //................................................................. // At this point, the app should be uncompressed to the "installing" // directory and ready to go. //................................................................. // Finally, under the right conditions, we delete the existing install // of the app and move the "installing" directory over it. info.moved = false; gchar * source_path = g_build_filename( info.app_directory.c_str(), "source", NULL ); free_later( source_path ); bool source_exists = g_file_test( source_path, G_FILE_TEST_EXISTS ); // If the source directory exists and the app is locked, we can // delete the source directory if ( source_exists && info.locked ) { if ( ! recursive_delete_path( source_path ) ) { throw String( "FAILED TO DELETE PREVIOUS APP SOURCE" ); } source_exists = false; } // If the source directory does not already exist, or we deleted in the // previous step, we can rename the install directory. if ( ! source_exists ) { if ( 0 != g_rename( unzip_path, source_path ) ) { throw String( "FAILED TO RENAME INSTALL DIRECTORY TO SOURCE DIRECTORY" ); } info.moved = true; } // Once this is done, the caller needs to call 'complete_install'. This will // move the app to its final resting place (if necessary) and also add its // entry to the system database. g_debug( "FINISHED INSTALL OF %s TO %s", info.app_id.c_str(), info.moved ? source_path : unzip_path ); info.status = Installer::Info::FINISHED; info.install_directory = unzip_path; info.app_directory = source_path; send_progress(); // Caller is also reponsible for getting rid of the original zip file. } catch( const String & e ) { g_warning( "FAILED TO INSTALL %s FROM %s : %s", info.app_id.c_str(), info.source_file.c_str(), e.c_str() ); info.status = Installer::Info::FAILED; send_progress( ); } // Close the zip file if ( zip ) { CloseZip( zip ); } // Always return true - to keep the thread running }
int utf8_luacall_utf8_sub(lua_State *l) { /// Reimplements lua's sub, but with unicode char indexes (the regular /// sub is not unicode aware and supports byte indexes only). /// Will throw error for any strings that aren't valid utf-8. luaL_checkstack(l, 4, ""); if (lua_type(l, 1) != LUA_TSTRING) { lua_pushstring(l, "invalid argument #1: not a string"); return lua_error(l); } if (lua_type(l, 2) != LUA_TNUMBER) { lua_pushstring(l, "invalid argument #2: not a number"); return lua_error(l); } if (lua_type(l, 3) != LUA_TNUMBER && lua_type(l, 3) != LUA_TNIL && lua_type(l, 3) != LUA_TNONE) { lua_pushstring(l, "invalid argument #3: not a number"); return lua_error(l); } size_t bufsize; const unsigned char *buf = (unsigned char*)luaL_checklstring(l, 1, &bufsize); if (!utf8_is_valid(buf, bufsize)) { lua_pushstring(l, "not a valid utf-8 string"); return lua_error(l); } // obtain start, end: int start = (int)lua_tonumber(l, 2); int end = -1; if (lua_type(l, 3) == LUA_TNUMBER) { end = (int)lua_tonumber(l, 3); } size_t length = utf8_length(buf, bufsize); if (start < 0) { start = (length + 1) + start; } if (end < 0) { end = (length + 1) + end; } // enforce sane limits: if (start < 1) {start = 1;} if (end > (int)length) {end = length;} if (start > (int)length || end < 1 || end < start) { // empty string. lua_pushstring(l, ""); return 1; } // obtain the result: UChar32 c; size_t startbytepos, endbytepos; int currentpos = 1; int i = 0; while (i < (int)bufsize) { if (currentpos == start) { startbytepos = i; } if (currentpos == end) { endbytepos = i + 1; break; } U8_NEXT(buf, i, bufsize, c); currentpos = currentpos + 1; } assert(endbytepos > startbytepos); char *resultbuf = malloc(1 + endbytepos - startbytepos); if (!resultbuf) { lua_pushstring(l, "allocation of end result failed"); return lua_error(l); } free_later(resultbuf); memcpy(resultbuf, buf + startbytepos, endbytepos - startbytepos); resultbuf[endbytepos - startbytepos] = 0; lua_pushstring(l, resultbuf); dont_free_later(resultbuf); free(resultbuf); return 1; }
virtual int decode( const char * filename, TPImage * image ) { if ( ! enabled() ) { tplog( " EXTERNAL IMAGE DECODER IS DISABLED" ); return TP_IMAGE_UNSUPPORTED_FORMAT; } std::ifstream stream; stream.open( filename, std::ios_base::in | std::ios_base::binary ); if ( ! stream.good() ) { stream.close(); return TP_IMAGE_DECODE_FAILED; } // We read the first few bytes of the file and pass that to the decoder // to see if it can detect the image format and tell us that it is // supported. // This attempts to optimize by not reading in the whole file before we // know whether the decoder supports it. static gsize header_size = 64; char header[ header_size ]; stream.read( header, header_size ); tplog( " INVOKING EXTERNAL DECODER TO DETECT IMAGE FORMAT WITH %d BYTES", stream.gcount() ); int r = decoder( header, stream.gcount(), NULL, decoder_data ); tplog( " EXTERNAL DECODER RETURNED %d", r ); if ( r != TP_IMAGE_SUPPORTED_FORMAT ) { stream.close(); // Return unsupported format so that we will try other decoders return TP_IMAGE_UNSUPPORTED_FORMAT; } // The decoder says that it supports the format, so we load // the whole file into memory and call the decoder again. stream.seekg( 0, std::ios::end ); if ( stream.fail() ) { stream.close(); return TP_IMAGE_DECODE_FAILED; } std::ios::streampos pos = stream.tellg(); if ( pos == -1 ) { stream.close(); return TP_IMAGE_DECODE_FAILED; } gchar * buffer = g_new( gchar, pos ); if ( ! buffer ) { stream.close(); return TP_IMAGE_DECODE_FAILED; } FreeLater free_later( buffer ); stream.seekg( 0 ); stream.read( buffer, pos ); if ( stream.fail() ) { stream.close(); return TP_IMAGE_DECODE_FAILED; } return decode( buffer, pos, image ); }