def _temporary_vfs(filenames_and_contents): """Creates a temporary VFS containing one or more files. Args: filenames_and_contents: A dict containing `{filename: contents}` pairs. The length of each filename must not exceed 98 characters. Yields: A `types.MJVFS` instance. Raises: Error: If a file cannot be added to the VFS, or if an error occurs when looking up the filename. ValueError: If the length of a filename exceeds 98 characters. """ vfs = types.MJVFS() mjlib.mj_defaultVFS(vfs) for filename, contents in six.iteritems(filenames_and_contents): if len(filename) > _MAX_VFS_FILENAME_CHARACTERS: raise ValueError( _VFS_FILENAME_TOO_LONG.format( length=len(filename), limit=_MAX_VFS_FILENAME_CHARACTERS, filename=filename)) filename = util.to_binary_string(filename) contents = util.to_binary_string(contents) _, extension = os.path.splitext(filename) # For XML files we need to append a NULL byte, otherwise MuJoCo's parser # can sometimes read past the end of the string. However, we should *not* # do this for other file types (in particular for STL meshes, where this # causes MuJoCo's compiler to complain that the file size is incorrect). append_null = extension.lower() == b".xml" num_bytes = len(contents) + append_null retcode = mjlib.mj_makeEmptyFileVFS(vfs, filename, num_bytes) if retcode == 1: raise Error("Failed to create {!r}: VFS is full.".format(filename)) elif retcode == 2: raise Error( "Failed to create {!r}: duplicate filename.".format(filename)) file_index = mjlib.mj_findFileVFS(vfs, filename) if file_index == -1: raise Error("Could not find {!r} in the VFS".format(filename)) vf = vfs.filedata[file_index] vf_as_char_arr = ctypes.cast(vf, ctypes.POINTER(ctypes.c_char * num_bytes)) vf_as_char_arr.contents[:len(contents)] = contents if append_null: vf_as_char_arr.contents[-1] = _NULL try: yield vfs finally: mjlib.mj_deleteVFS(vfs) # Ensure that we free the VFS afterwards.
def testFileNameTrimming(self): original_filename = ( 'THIS_IS_AN_EXTREMELY_LONG_FILENAME_THAT_WOULD_CAUSE_MUJOCO_TO_COMPLAIN' '_THAT_ITS_INTERNAL_LENGTH_LIMIT_IS_EXCEEDED_IF_NOT_TRIMMED_DOWN') extension = '.some_extension' asset = attribute.Asset( contents='', extension=extension, prefix=original_filename) vfs_filename = asset.get_vfs_filename() self.assertLen(vfs_filename, constants.MAX_VFS_FILENAME_LENGTH) vfs = types.MJVFS() mjlib.mj_defaultVFS(vfs) success_code = 0 retval = mjlib.mj_makeEmptyFileVFS( vfs, util.to_binary_string(vfs_filename), 1) self.assertEqual(retval, success_code) mjlib.mj_deleteVFS(vfs)