/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.file.formats.android.dex.format;

import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.file.formats.android.dex.util.Leb128;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;

import java.io.ByteArrayInputStream;
import java.io.IOException;

public class StringDataItem implements StructConverter {

	private int stringLength;
	private int lebLength;
	private int actualLength;
	private String string;

	public StringDataItem( StringIDItem stringItem, BinaryReader reader ) throws IOException {
		long oldIndex = reader.getPointerIndex( );
		try {
			reader.setPointerIndex( stringItem.getStringDataOffset( ) );
			stringLength = Leb128.readUnsignedLeb128( reader.readByteArray( stringItem.getStringDataOffset( ), 5 ) );

			lebLength = Leb128.unsignedLeb128Size( stringLength );

			reader.readNextByteArray( lebLength );// consume leb...

			actualLength = computeActualLength( reader );

			byte [] stringBytes = reader.readNextByteArray( actualLength );

			ByteArrayInputStream in = new ByteArrayInputStream( stringBytes );

			char [] out = new char[ stringLength ];

			string = ModifiedUTF8.decode( in, out );
		}
		finally {
			reader.setPointerIndex( oldIndex );
		}
	}

	public String getString( ) {
		return string;
	}

	@Override
	public DataType toDataType( ) throws DuplicateNameException, IOException {
		Structure structure = new StructureDataType( "string_data_item_" + actualLength, 0 );
		structure.add( new ArrayDataType( BYTE, lebLength, BYTE.getLength( ) ), "utf16_size", null );
		structure.add( UTF8, actualLength, "data", null );
		structure.setCategoryPath( new CategoryPath( "/dex/string_data_item" ) );
		return structure;
	}

	private int computeActualLength( BinaryReader reader ) throws IOException {
		int count = 0;
		while ( count < 0x200000 ) {// don't run forever!
			if ( reader.readByte( reader.getPointerIndex( ) + count ) == 0x0 ) {
				break;
			}
			++count;
		}
		return count + 1;
	}

}