NPK_PACKAGE npk_package_open( NPK_CSTR filename, NPK_TEAKEY teakey[4] ) { NPK_PACKAGEBODY* pb = NULL; NPK_RESULT res; res = npk_package_alloc( (NPK_PACKAGE*)&pb, teakey ); if( res != NPK_SUCCESS ) return NULL; if( npk_package_init( pb ) != NPK_SUCCESS ) goto npk_package_open_return_null_with_free; if( npk_open( &pb->handle_, filename, false, false ) != NPK_SUCCESS ) goto npk_package_open_return_null_with_free; res = __npk_package_open( pb, filename, 0, teakey ); if( res != NPK_SUCCESS ) goto npk_package_open_return_null_with_free; return (NPK_PACKAGE*)pb; npk_package_open_return_null_with_free: if( pb ) npk_package_close( pb ); return NULL; }
NPK_RESULT npk_entity_export( NPK_ENTITY entity, NPK_CSTR filename, bool forceoverwrite ) { void* buf; NPK_HANDLE handle; NPK_ENTITYBODY* eb = entity; NPK_RESULT res; if( !entity ) return npk_error( NPK_ERROR_EntityIsNull ); buf = malloc( eb->info_.originalSize_ ); if( !buf ) return npk_error( NPK_ERROR_NotEnoughMemory ); if( !( res = npk_entity_read( eb, buf ) ) ) return res; if( ( res = npk_open( &handle, filename, true, true ) ) != NPK_SUCCESS ) { if( !forceoverwrite ) return res; if( ( res = npk_open( &handle, filename, true, false ) ) != NPK_SUCCESS ) return res; } if( ( res = npk_write( handle, buf, eb->info_.originalSize_, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) return res; if( ( res = npk_close( handle ) ) != NPK_SUCCESS ) return res; npk_set_filetime( filename, eb->info_.modified_ ); free( buf ); return NPK_SUCCESS; }
NPK_RESULT npk_package_save( NPK_PACKAGE package, NPK_CSTR filename, bool forceoverwrite ) { NPK_PACKAGEBODY* pb = package; NPK_ENTITYBODY* eb = NULL; NPK_RESULT res; bool bUseTemporaryFile = false; NPK_SIZE len; int savecount = 0; NPK_STR savefilename = NULL; int savefilehandle; NPK_CHAR* buf; NPK_CHAR* buf_pos; NPK_PACKAGEINFO_V23 header_v23; if( !package ) return npk_error( NPK_ERROR_PackageIsNull ); if( !filename ) return npk_error( NPK_ERROR_PackageHasNoName ); if( ( res = npk_open( &savefilehandle, filename, true, true ) ) == NPK_SUCCESS ) { npk_alloc_copy_string( &savefilename, filename ); } else { if( res != NPK_ERROR_FileAlreadyExists ) return res; if( !forceoverwrite ) return res; len = (NPK_SIZE)strlen( filename ); savefilename = malloc( sizeof(NPK_CHAR)*(len+2) ); if( savefilename == NULL ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); strncpy( savefilename, filename, len ); savefilename[len+0] = '_'; savefilename[len+1] = '\0'; bUseTemporaryFile = true; if( ( res = npk_open( &savefilehandle, savefilename, true, false ) ) != NPK_SUCCESS ) return res; } strncpy( pb->info_.signature_, NPK_SIGNATURE, sizeof(NPK_CHAR)*4 ); pb->info_.version_ = NPK_VERSION_CURRENT; pb->info_.entityDataOffset_ = sizeof(NPK_PACKAGEINFO) + sizeof(NPK_PACKAGEINFO_V23); npk_seek( savefilehandle, (long)pb->info_.entityDataOffset_, SEEK_SET ); eb = pb->pEntityHead_; while( eb != NULL ) { if( g_callbackfp ) if( (g_callbackfp)( NPK_ACCESSTYPE_WRITE, NPK_PROCESSTYPE_PACKAGE, filename, savecount, pb->info_.entityCount_ ) == false ) return( npk_error( NPK_ERROR_CancelByCallback ) ); npk_entity_write( eb, savefilehandle ); ++savecount; eb = eb->next_; } pb->info_.entityInfoOffset_ = npk_tell( savefilehandle ); pb->info_.entityCount_ = savecount; eb = pb->pEntityHead_; // version 24, Take single encryption to whole entity headers buf = malloc( (sizeof(NPK_ENTITYINFO)+260)*savecount ); // 260 = MAX_PATH on windows, isn't it enough? if( !buf ) return( npk_error( NPK_ERROR_NotEnoughMemory ) ); buf_pos = buf; while( eb != NULL ) { memcpy( buf_pos, &eb->info_, sizeof(NPK_ENTITYINFO) ); buf_pos += sizeof(NPK_ENTITYINFO); memcpy( buf_pos, eb->name_, sizeof(NPK_CHAR)*eb->info_.nameLength_ ); buf_pos += sizeof(NPK_CHAR)*eb->info_.nameLength_; eb = eb->next_; } if( ( res = npk_write_encrypt( pb->teakey_, savefilehandle, buf, buf_pos - buf, g_callbackfp, NPK_PROCESSTYPE_ENTITYHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; NPK_SAFE_FREE( buf ); npk_seek( savefilehandle, 0, SEEK_SET ); if( ( res = npk_write( savefilehandle, &pb->info_, sizeof(NPK_PACKAGEINFO), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; // version 23, Write the package timestamp for other applications // TODO:reveal the return type of 'time' function on 64bit mac os time( (time_t*)&header_v23.modified_ ); if( ( res = npk_write( savefilehandle, &header_v23, sizeof(NPK_PACKAGEINFO_V23), g_callbackfp, NPK_PROCESSTYPE_PACKAGEHEADER, g_callbackSize, savefilename ) ) != NPK_SUCCESS ) return res; npk_flush( savefilehandle ); npk_close( pb->handle_ ); if( bUseTemporaryFile ) { npk_close( savefilehandle ); remove( filename ); rename( savefilename, filename ); if( (res = npk_open( &pb->handle_, filename, false, false ) ) != NPK_SUCCESS ) return res; } else { pb->handle_ = savefilehandle; } NPK_SAFE_FREE( savefilename ); return NPK_SUCCESS; }
NPK_RESULT npk_entity_write( NPK_ENTITY entity, NPK_HANDLE handle ) { NPK_PACKAGEBODY* pb; NPK_ENTITYBODY* eb = entity; NPK_RESULT res; bool skipProcessing; void* buf = NULL; void* buf_for_zlib = NULL; NPK_SIZE size, endpos, startpos; int filehandle; int z_res; if( !eb ) return npk_error( NPK_ERROR_EntityIsNull ); pb = eb->owner_; skipProcessing = false; if( eb->localname_ != NULL ) { // read native file and write if( ( res = npk_open( &filehandle, eb->localname_, false, false ) ) != NPK_SUCCESS ) return res; endpos = npk_seek( filehandle, 0, SEEK_END ); startpos = npk_seek( filehandle, 0, SEEK_SET ); size = endpos - startpos; if( size == 0 ) return npk_error( NPK_ERROR_ZeroFileSize ); eb->info_.originalSize_ = size; buf = malloc( size ); if( ( res = npk_read( filehandle, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; npk_close( filehandle ); npk_get_filetime( eb->localname_, &eb->info_.modified_ ); NPK_SAFE_FREE( eb->localname_ ); } else { if( eb->newflag_ != eb->info_.flag_ ) { // read entity and write size = eb->info_.originalSize_; buf = malloc( size ); npk_entity_read( eb, buf ); } else { // just copy size = eb->info_.size_; buf = malloc( size ); npk_seek( pb->handle_, (long)eb->info_.offset_+pb->offsetJump_, SEEK_SET ); if( ( res = npk_read( pb->handle_, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; skipProcessing = true; } } if( !skipProcessing ) { // Encode before compress, before v21 if( ( eb->newflag_ & NPK_ENTITY_ENCRYPT ) && !( eb->newflag_ & NPK_ENTITY_REVERSE ) ) tea_encode_buffer((char*)buf, (int)size, pb->teakey_ ); if( eb->newflag_ & NPK_ENTITY_COMPRESS ) { if( size >= NPK_MIN_SIZE_ZIPABLE ) { unsigned long compressedSize = (unsigned long)(sizeof(char) * size * 1.1 + 12); // margin rules from zlib/compress.c buf_for_zlib = malloc( compressedSize ); #ifdef Z_PREFIX z_res = z_compress( (Bytef*)buf_for_zlib, (z_uLong*)&compressedSize, (const Bytef*)buf, (z_uLong)size ); #else z_res = compress( (Bytef*)buf_for_zlib, (uLong*)&compressedSize, (const Bytef*)buf, (uLong)size ); #endif if( ( z_res == Z_OK ) && ( compressedSize < size ) ) { free( buf ); buf = buf_for_zlib; buf_for_zlib = NULL; size = compressedSize; } else // not suitable to compress { free( buf_for_zlib ); eb->newflag_ &= !NPK_ENTITY_COMPRESS; } } } // Encode after compress, after v21 if( ( eb->newflag_ & NPK_ENTITY_ENCRYPT ) && ( eb->newflag_ & NPK_ENTITY_REVERSE ) ) tea_encode_buffer((char*)buf, (int)size, pb->teakey_ ); } eb->info_.size_ = size; eb->info_.offset_ = npk_tell( handle ); if( ( res = npk_write( handle, buf, size, g_callbackfp, NPK_PROCESSTYPE_ENTITY, g_callbackSize, eb->name_ ) ) != NPK_SUCCESS ) goto npk_entity_write_return_with_free; free( buf ); eb->info_.flag_ = eb->newflag_; return NPK_SUCCESS; npk_entity_write_return_with_free: NPK_SAFE_FREE( buf ); NPK_SAFE_FREE( buf_for_zlib ); return res; }