AssetDatabase.CreateAsset creates extensionless assets

Hi everybody.

I’m extracting jpegs from a file format that contains other data along with several bundled jpegs. I’ve found and extracted the byte data, turned them into Texture2D objects, which work great. Now I want to save them:

AssetDatabase.CreateAsset(nt, "Assets/Skins/"+skinName+sbs+".asset");
Debug.Log(AssetDatabase.GetAssetPath(nt));

Looks ok, no? sbs contains a leading ‘/’, so the aim is to end up with e.g. “Assets/Skins/bonemachine/navpane.asset”.

But the asset that is created has no extension. If I go and rename the file to add the .asset extension, it works fine. So why is CreateAsset clipping off the extension?

Here’s the full code:

	void ReadFile(TextAsset target)
	{
		Stream s = new MemoryStream(target.bytes);
		BinaryReader br = new BinaryReader(s);
		// some hard offsets
		uint ptr = 0x70;
		uint skip1 = 0xc4 - ptr;
		uint skip = 0xd4 - ptr;
		AssetDatabase.StartAssetEditing();
		do {
			s.Seek(ptr, SeekOrigin.Begin); // go to the start of the next filename
			if((char)br.ReadByte() == '/') // make sure it's a filename - if not then we've finished
			{
				byte[] fn = br.ReadBytes(54); // hard max length for filenames
				string filename = System.Text.Encoding.UTF8.GetString(fn);
				// read four bytes for address, then four for length
				s.Seek(ptr + skip1, SeekOrigin.Begin); // skip to address location
				byte[] ptrs = br.ReadBytes(8);
				int address = ptrs[0] + (ptrs[1] << 8) + (ptrs[2] << 16) + (ptrs[3] << 24);
				int length = ptrs[4] + (ptrs[5] << 8) + (ptrs[6] << 16) + (ptrs[7] << 24);
				
				s.Seek(address, SeekOrigin.Begin); // i herd u like data so i put a file in ur file
				int header = s.ReadByte() + (s.ReadByte() << 8);
				if (header == 0xd8ff) // check it's a jpeg, if not, we don't care FOR NOW
				{
					s.Seek(address, SeekOrigin.Begin); // can't remember if i need this after prev reads
					byte[] jpeg = br.ReadBytes(length);
					Texture2D nt = new Texture2D(1,1);
					nt.LoadImage(jpeg);
					textures.Add(nt); // ignore this
					string sbs = filename.Substring(filename.LastIndexOf('/'));
					if (!Directory.Exists("Assets/Skins")) AssetDatabase.CreateFolder("Assets", "Skins");
					if (!Directory.Exists("Assets/Skins/"+skinName)) AssetDatabase.CreateFolder("Assets/Skins", skinName); // not sure if assetdatabase will create folders automatically
					AssetDatabase.CreateAsset(nt, "Assets/Skins/"+skinName+sbs+".asset"); // hmm looks like I DEFINITELY ADDED THE EXTENSION
					Debug.Log(AssetDatabase.GetAssetPath(nt)); // this reports filename with no extension
				}
			}
			else break;
			ptr += skip;
		}
		while(true);
		AssetDatabase.StopAssetEditing();
		AssetDatabase.SaveAssets();
	}

The error is at line 14, where the byte array is converted into a string. Since it contains a bunch of zeroes, these are converted into invalid characters in the string, which don’t show up as characters when viewed in the debugger but cause an exception in standard .NET file creation. In Unity’s file handling system an unreported error silently causes the file to be created but without an extension, in this case, for some reason, without even logging a warning. Probably as soon as it encounters an invalid character, it clips the filename at that point.

Here is code that fixes that:

				int nullterminator = 0;
				for (int i = 0; i < fn.Length; i++) {
					if (fn *== 0)*
  •  			{nullterminator = i; break;}*
    
  •  		}*
    
  •  		string filename = System.Text.Encoding.ASCII.GetString(fn,0,nullterminator);//System.Text.Encoding.UTF8.GetString(fn);*