bool LLLFSThread::Request::processRequest() { bool complete = false; if (mOperation == FILE_READ) { llassert(mOffset >= 0); apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_RB, mThread->mAPRPoolp); if (!filep) { llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; mBytesRead = 0; // fail return true; } S32 off; if (mOffset < 0) off = ll_apr_file_seek(filep, APR_END, 0); else off = ll_apr_file_seek(filep, APR_SET, mOffset); llassert_always(off >= 0); mBytesRead = ll_apr_file_read(filep, mBuffer, mBytes ); apr_file_close(filep); complete = true; // llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl; } else if (mOperation == FILE_WRITE) { apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (mOffset < 0) flags |= APR_APPEND; apr_file_t* filep = ll_apr_file_open(mFileName, flags, mThread->mAPRPoolp); if (!filep) { llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; mBytesRead = 0; // fail return true; } if (mOffset >= 0) { S32 seek = ll_apr_file_seek(filep, APR_SET, mOffset); if (seek < 0) { apr_file_close(filep); llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl; mBytesRead = 0; // fail return true; } } mBytesRead = ll_apr_file_write(filep, mBuffer, mBytes ); complete = true; apr_file_close(filep); // llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl; } else { llerrs << "LLLFSThread::unknown operation: " << (S32)mOperation << llendl; } return complete; }
S32 ll_apr_file_write_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) { if (pool == NULL) pool = gAPRPoolp; apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (offset < 0) { flags |= APR_APPEND; offset = 0; } apr_file_t* filep = ll_apr_file_open(filename, flags, pool); if (!filep) { return 0; } if (offset > 0) { offset = ll_apr_file_seek(filep, APR_SET, offset); } S32 bytes_written; if (offset < 0) { bytes_written = 0; } else { bytes_written = ll_apr_file_write(filep, buf, nbytes ); } apr_file_close(filep); return bytes_written; }
S32 ll_apr_file_read_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) { if (pool == NULL) pool = gAPRPoolp; apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool); if (!filep) { return 0; } S32 off; if (offset < 0) off = ll_apr_file_seek(filep, APR_END, 0); else off = ll_apr_file_seek(filep, APR_SET, offset); S32 bytes_read; if (off < 0) { bytes_read = 0; } else { bytes_read = ll_apr_file_read(filep, buf, nbytes ); } apr_file_close(filep); return bytes_read; }
void upload_new_resource(const std::string& src_filename, std::string name, std::string desc, S32 compression_info, LLAssetType::EType destination_folder_type, LLInventoryType::EType inv_type, U32 next_owner_perm, const std::string& display_name, LLAssetStorage::LLStoreAssetCallback callback, void *userdata) { // Generate the temporary UUID. std::string filename = gDirUtilp->getTempFilename(); LLTransactionID tid; LLAssetID uuid; LLStringUtil::format_map_t args; std::string exten = gDirUtilp->getExtension(src_filename); LLAssetType::EType asset_type = LLAssetType::AT_NONE; std::string error_message; BOOL error = FALSE; if (exten.empty()) { std::string short_name = gDirUtilp->getBaseFileName(filename); // No extension error_message = llformat( "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", short_name.c_str()); args["[FILE]"] = short_name; upload_error(error_message, "NofileExtension", filename, args); return; } else if( exten == "bmp") { asset_type = LLAssetType::AT_TEXTURE; if (!LLViewerImageList::createUploadFile(src_filename, filename, IMG_CODEC_BMP )) { error_message = llformat( "Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImageBase::getLastError().c_str()); args["[FILE]"] = src_filename; args["[ERROR]"] = LLImageBase::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } } else if( exten == "tga") { asset_type = LLAssetType::AT_TEXTURE; if (!LLViewerImageList::createUploadFile(src_filename, filename, IMG_CODEC_TGA )) { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImageBase::getLastError().c_str()); args["[FILE]"] = src_filename; args["[ERROR]"] = LLImageBase::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } } else if( exten == "jpg" || exten == "jpeg") { asset_type = LLAssetType::AT_TEXTURE; if (!LLViewerImageList::createUploadFile(src_filename, filename, IMG_CODEC_JPEG )) { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImageBase::getLastError().c_str()); args["[FILE]"] = src_filename; args["[ERROR]"] = LLImageBase::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } } else if( exten == "png") { asset_type = LLAssetType::AT_TEXTURE; if (!LLViewerImageList::createUploadFile(src_filename, filename, IMG_CODEC_PNG )) { error_message = llformat("Problem with file %s:\n\n%s\n", src_filename.c_str(), LLImageBase::getLastError().c_str()); args["[FILE]"] = src_filename; args["[ERROR]"] = LLImageBase::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); return; } } else if(exten == "wav") { asset_type = LLAssetType::AT_SOUND; // tag it as audio S32 encode_result = 0; llinfos << "Attempting to encode wav as an ogg file" << llendl; encode_result = encode_vorbis_file(src_filename, filename); if (LLVORBISENC_NOERR != encode_result) { switch(encode_result) { case LLVORBISENC_DEST_OPEN_ERR: error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); args["[FILE]"] = filename; upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); break; default: error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); args["[FILE]"] = src_filename; upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); break; } return; } } else if(exten == "tmp") { // This is a generic .lin resource file asset_type = LLAssetType::AT_OBJECT; LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */ if (in) { // read in the file header char buf[16384]; /* Flawfinder: ignore */ S32 read; /* Flawfinder: ignore */ S32 version; if (fscanf(in, "LindenResource\nversion %d\n", &version)) { if (2 == version) { // *NOTE: This buffer size is hard coded into scanf() below. char label[MAX_STRING]; /* Flawfinder: ignore */ char value[MAX_STRING]; /* Flawfinder: ignore */ S32 tokens_read; while (fgets(buf, 1024, in)) { label[0] = '\0'; value[0] = '\0'; tokens_read = sscanf( /* Flawfinder: ignore */ buf, "%254s %254s\n", label, value); llinfos << "got: " << label << " = " << value << llendl; if (EOF == tokens_read) { fclose(in); error_message = llformat("corrupt resource file: %s", src_filename.c_str()); args["[FILE]"] = src_filename; upload_error(error_message, "CorruptResourceFile", filename, args); return; } if (2 == tokens_read) { if (! strcmp("type", label)) { asset_type = (LLAssetType::EType)(atoi(value)); } } else { if (! strcmp("_DATA_", label)) { // below is the data section break; } } // other values are currently discarded } } else { fclose(in); error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); args["[FILE]"] = src_filename; upload_error(error_message, "UnknownResourceFileVersion", filename, args); return; } } else { // this is an original binary formatted .lin file // start over at the beginning of the file fseek(in, 0, SEEK_SET); const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256; const S32 MAX_ASSET_NAME_LENGTH = 64; S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH; S16 type_num; // read in and throw out most of the header except for the type if (fread(buf, header_size, 1, in) != 1) { llwarns << "Short read" << llendl; } memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */ asset_type = (LLAssetType::EType)type_num; } // copy the file's data segment into another file for uploading LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ if (out) { while((read = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ { if (fwrite(buf, 1, read, out) != read) { llwarns << "Short write" << llendl; } } fclose(out); } else { fclose(in); error_message = llformat( "Unable to create output file: %s", filename.c_str()); args["[FILE]"] = filename; upload_error(error_message, "UnableToCreateOutputFile", filename, args); return; } fclose(in); } else { llinfos << "Couldn't open .lin file " << src_filename << llendl; } } else if (exten == "bvh") { error_message = llformat("We do not currently support bulk upload of animation files\n"); upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); return; } else { // Unknown extension // *TODO: Translate? error_message = llformat("Unknown file extension .%s\nExpected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh", exten.c_str()); error = TRUE;; } // gen a new transaction ID for this asset tid.generate(); if (!error) { uuid = tid.makeAssetID(gAgent.getSecureSessionID()); // copy this file into the vfs for upload S32 file_size; apr_file_t* fp = ll_apr_file_open(filename, LL_APR_RB, &file_size); if (fp) { LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); file.setMaxSize(file_size); const S32 buf_size = 65536; U8 copy_buf[buf_size]; while ((file_size = ll_apr_file_read(fp, copy_buf, buf_size))) { file.write(copy_buf, file_size); } apr_file_close(fp); } else { error_message = llformat( "Unable to access output file: %s", filename.c_str()); error = TRUE; } } if (!error) { std::string t_disp_name = display_name; if (t_disp_name.empty()) { t_disp_name = src_filename; } upload_new_resource(tid, asset_type, name, desc, compression_info, // tid destination_folder_type, inv_type, next_owner_perm, display_name, callback, userdata); } else { llwarns << error_message << llendl; LLStringUtil::format_map_t args; args["[ERROR_MESSAGE]"] = error_message; gViewerWindow->alertXml("ErrorMessage", args); if(LLFile::remove(filename) == -1) { lldebugs << "unable to remove temp file" << llendl; } LLFilePicker::instance().reset(); } }
BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname) { ov_callbacks vfs_callbacks; vfs_callbacks.read_func = vfs_read; vfs_callbacks.seek_func = vfs_seek; vfs_callbacks.close_func = vfs_close; vfs_callbacks.tell_func = vfs_tell; char pcmout[4096]; /*Flawfinder: ignore*/ unsigned char temp[64]; /*Flawfinder: ignore*/ LLVFile *in_vfile; U32 data_length = 0; llinfos << "Vorbis decode from vfile: " << in_uuid << llendl; in_vfile = new LLVFile(vfs, in_uuid, LLAssetType::AT_SOUND); if (! in_vfile->getSize()) { llwarning("unable to open vorbis source vfile for reading",0); return(FALSE); } apr_file_t* outfp = ll_apr_file_open(out_fname,LL_APR_WPB); if (!outfp) { llwarning("unable to open vorbis destination file for writing",0); return(FALSE); } else { // write the .wav format header //"RIFF" temp[0] = 0x52; temp[1] = 0x49; temp[2] = 0x46; temp[3] = 0x46; // length = datalen + 36 (to be filled in later) temp[4] = 0x00; temp[5] = 0x00; temp[6] = 0x00; temp[7] = 0x00; //"WAVE" temp[8] = 0x57; temp[9] = 0x41; temp[10] = 0x56; temp[11] = 0x45; // "fmt " temp[12] = 0x66; temp[13] = 0x6D; temp[14] = 0x74; temp[15] = 0x20; // chunk size = 16 temp[16] = 0x10; temp[17] = 0x00; temp[18] = 0x00; temp[19] = 0x00; // format (1 = PCM) temp[20] = 0x01; temp[21] = 0x00; // number of channels temp[22] = 0x01; temp[23] = 0x00; // samples per second temp[24] = 0x44; temp[25] = 0xAC; temp[26] = 0x00; temp[27] = 0x00; // average bytes per second temp[28] = 0x88; temp[29] = 0x58; temp[30] = 0x01; temp[31] = 0x00; // bytes to output at a single time temp[32] = 0x02; temp[33] = 0x00; // 16 bits per sample temp[34] = 0x10; temp[35] = 0x00; // "data" temp[36] = 0x64; temp[37] = 0x61; temp[38] = 0x74; temp[39] = 0x61; // these are the length of the data chunk, to be filled in later temp[40] = 0x00; temp[41] = 0x00; temp[42] = 0x00; temp[43] = 0x00; ll_apr_file_write(outfp, temp, 44); } OggVorbis_File vf; int eof=0; int current_section; int r = ov_open_callbacks(in_vfile, &vf, NULL, 0, vfs_callbacks); if(r < 0) { llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << in_uuid << llendl; return(FALSE); } { char **ptr=ov_comment(&vf,-1)->user_comments; // vorbis_info *vi=ov_info(&vf,-1); while(*ptr){ fprintf(stderr,"%s\n",*ptr); ++ptr; } // fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate); // fprintf(stderr,"\nDecoded length: %ld samples\n", (long)ov_pcm_total(&vf,-1)); // fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor); } while(!eof){ long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,¤t_section); if (ret == 0) { /* EOF */ eof=1; // llinfos << "Vorbis EOF" << llendl; } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ llwarning("Error in vorbis stream",0); break; } else { // llinfos << "Vorbis read " << ret << "bytes" << llendl; /* we don't bother dealing with sample rate changes, etc, but. you'll have to*/ data_length += ll_apr_file_write(outfp, pcmout, ret); } } ov_clear(&vf); // write "data" chunk length ll_apr_file_seek(outfp,APR_SET,40); ll_apr_file_write(outfp,&data_length,4); // write overall "RIFF" length data_length += 36; ll_apr_file_seek(outfp,APR_SET,4); ll_apr_file_write(outfp,&data_length,1*4); // F**K!!! Vorbis encode/decode messes up loop point transitions (pop) // do a cheap-and-cheesy crossfade S16 *samplep; S32 i; S32 fade_length; fade_length = llmin((S32)128,(S32)(data_length-36)/8); ll_apr_file_seek(outfp,APR_SET,44); ll_apr_file_read(outfp, pcmout,2*fade_length); //read first 16 samples samplep = (S16 *)pcmout; for (i = 0 ;i < fade_length; i++) { *samplep++ = ((F32)*samplep * ((F32)i/(F32)fade_length)); } ll_apr_file_seek(outfp,APR_SET,44); ll_apr_file_write(outfp,pcmout,2*fade_length); //write back xfaded first 16 samples ll_apr_file_seek(outfp,APR_END,-fade_length*2); ll_apr_file_read(outfp, pcmout,2*fade_length); //read last 16 samples samplep = (S16 *)pcmout; for (i = fade_length-1 ; i >= 0; i--) { *samplep++ = ((F32)*samplep * ((F32)i/(F32)fade_length)); } ll_apr_file_seek(outfp,SEEK_END,-fade_length*2); ll_apr_file_write(outfp,pcmout,2*fade_length); //write back xfaded last 16 samples apr_file_close(outfp); if ((36 == data_length) || (!(eof))) { llwarning("BAD Vorbis DECODE!, removing .wav!",0); LLFile::remove(out_fname); return (FALSE); } // fprintf(stderr,"Done.\n"); return(TRUE); }
apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags) { return ll_apr_file_open(filename, flags, NULL, NULL); }
apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep) { return ll_apr_file_open(filename, flags, sizep, NULL); }
//----------------------------------------------------------------------------- // postBuild() //----------------------------------------------------------------------------- BOOL LLFloaterAnimPreview::postBuild() { LLRect r; LLKeyframeMotion* motionp = NULL; LLBVHLoader* loaderp = NULL; if (!LLFloaterNameDesc::postBuild()) { return FALSE; } childSetCommitCallback("name_form", onCommitName, this); childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onBtnOK, this); setDefaultBtn(); mPreviewRect.set(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT, getRect().getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f); S32 y = mPreviewRect.mTop + BTN_HEIGHT; S32 btn_left = PREVIEW_HPAD; r.set( btn_left, y, btn_left + 32, y - BTN_HEIGHT ); mPlayButton = getChild<LLButton>( "play_btn"); if (!mPlayButton) { mPlayButton = new LLButton(std::string("play_btn"), LLRect(0,0,0,0)); } mPlayButton->setClickedCallback(onBtnPlay); mPlayButton->setCallbackUserData(this); mPlayButton->setImages(std::string("button_anim_play.tga"), std::string("button_anim_play_selected.tga")); mPlayButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); mPlayButton->setScaleImage(TRUE); mStopButton = getChild<LLButton>( "stop_btn"); if (!mStopButton) { mStopButton = new LLButton(std::string("stop_btn"), LLRect(0,0,0,0)); } mStopButton->setClickedCallback(onBtnStop); mStopButton->setCallbackUserData(this); mStopButton->setImages(std::string("button_anim_stop.tga"), std::string("button_anim_stop_selected.tga")); mStopButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); mStopButton->setScaleImage(TRUE); r.set(r.mRight + PREVIEW_HPAD, y, getRect().getWidth() - PREVIEW_HPAD, y - BTN_HEIGHT); //childSetCommitCallback("playback_slider", onSliderMove, this); childHide("bad_animation_text"); //childSetCommitCallback("preview_base_anim", onCommitBaseAnim, this); //childSetValue("preview_base_anim", "Standing"); //childSetCommitCallback("priority", onCommitPriority, this); //childSetCommitCallback("loop_check", onCommitLoop, this); //childSetCommitCallback("loop_in_point", onCommitLoopIn, this); //childSetValidate("loop_in_point", validateLoopIn); //childSetCommitCallback("loop_out_point", onCommitLoopOut, this); //childSetValidate("loop_out_point", validateLoopOut); //childSetCommitCallback("hand_pose_combo", onCommitHandPose, this); //childSetCommitCallback("emote_combo", onCommitEmote, this); //childSetValue("emote_combo", "[None]"); //childSetCommitCallback("ease_in_time", onCommitEaseIn, this); //childSetValidate("ease_in_time", validateEaseIn); //childSetCommitCallback("ease_out_time", onCommitEaseOut, this); //childSetValidate("ease_out_time", validateEaseOut); std::string exten = gDirUtilp->getExtension(mFilename); if (exten == "bvh") { // loading a bvh file // now load bvh file S32 file_size; apr_file_t* fp = ll_apr_file_open(mFilenameAndPath, LL_APR_RB, &file_size); if (!fp) { llwarns << "Can't open BVH file:" << mFilename << llendl; } else { char* file_buffer; file_buffer = new char[file_size + 1]; if (file_size == ll_apr_file_read(fp, file_buffer, file_size)) { file_buffer[file_size] = '\0'; llinfos << "Loading BVH file " << mFilename << llendl; loaderp = new LLBVHLoader(file_buffer); } apr_file_close(fp); delete[] file_buffer; } } if (loaderp && loaderp->isInitialized() && loaderp->getDuration() <= MAX_ANIM_DURATION) { // generate unique id for this motion mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); mAnimPreview = new LLPreviewAnimation(256, 256); // motion will be returned, but it will be in a load-pending state, as this is a new motion // this motion will not request an asset transfer until next update, so we have a chance to // load the keyframe data locally motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); // create data buffer for keyframe initialization S32 buffer_size = loaderp->getOutputSize(); U8* buffer = new U8[buffer_size]; LLDataPackerBinaryBuffer dp(buffer, buffer_size); // pass animation data through memory buffer loaderp->serialize(dp); dp.reset(); BOOL success = motionp && motionp->deserialize(dp); delete []buffer; if (success) { setAnimCallbacks() ; const LLBBoxLocal &pelvis_bbox = motionp->getPelvisBBox(); LLVector3 temp = pelvis_bbox.getCenter(); // only consider XY? //temp.mV[VZ] = 0.f; F32 pelvis_offset = temp.magVec(); temp = pelvis_bbox.getExtent(); //temp.mV[VZ] = 0.f; F32 pelvis_max_displacement = pelvis_offset + (temp.magVec() * 0.5f) + 1.f; F32 camera_zoom = LLViewerCamera::getInstance()->getDefaultFOV() / (2.f * atan(pelvis_max_displacement / PREVIEW_CAMERA_DISTANCE)); mAnimPreview->setZoom(camera_zoom); motionp->setName(childGetValue("name_form").asString()); mAnimPreview->getDummyAvatar()->startMotion(mMotionID); childSetMinValue("playback_slider", 0.0); childSetMaxValue("playback_slider", 1.0); childSetValue("loop_check", LLSD(motionp->getLoop())); childSetValue("loop_in_point", LLSD(motionp->getLoopIn() / motionp->getDuration() * 100.f)); childSetValue("loop_out_point", LLSD(motionp->getLoopOut() / motionp->getDuration() * 100.f)); childSetValue("priority", LLSD((F32)motionp->getPriority())); childSetValue("hand_pose_combo", LLHandMotion::getHandPoseName(motionp->getHandPose())); childSetValue("ease_in_time", LLSD(motionp->getEaseInDuration())); childSetValue("ease_out_time", LLSD(motionp->getEaseOutDuration())); setEnabled(TRUE); std::string seconds_string; seconds_string = llformat(" - %.2f seconds", motionp->getDuration()); setTitle(mFilename + std::string(seconds_string)); } else { delete mAnimPreview; mAnimPreview = NULL; mMotionID.setNull(); childSetValue("bad_animation_text", getString("failed_to_initialize")); } } else { if ( loaderp ) { if (loaderp->getDuration() > MAX_ANIM_DURATION) { LLUIString out_str = getString("anim_too_long"); out_str.setArg("[LENGTH]", llformat("%.1f", loaderp->getDuration())); out_str.setArg("[MAX_LENGTH]", llformat("%.1f", MAX_ANIM_DURATION)); childSetValue("bad_animation_text", out_str.getString()); } else { LLUIString out_str = getString("failed_file_read"); out_str.setArg("[STATUS]", loaderp->getStatus()); // *TODO:Translate childSetValue("bad_animation_text", out_str.getString()); } } //setEnabled(FALSE); mMotionID.setNull(); mAnimPreview = NULL; } refresh(); delete loaderp; return TRUE; }