content: /*
   * Copyright 2008 Android4ME
   *
   * 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
   *
   *     https://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 android.content.res;
  
  import java.io.IOException;
  
  /**
   * @author Dmitry Skiba
   * 
   * Block of strings, used in binary xml and arsc.
   * 
   * TODO:
   * - implement get()
   *
   */
  public class StringBlock {
  	
  	/**
  	 * Reads whole (including chunk type) string block from stream.
  	 * Stream must be at the chunk type.
  	 */
  	public static StringBlock read(IntReader reader) throws IOException {
  		ChunkUtil.readCheckType(reader,CHUNK_TYPE);
  		int chunkSize=reader.readInt();
  		int stringCount=reader.readInt();
  		int styleOffsetCount=reader.readInt();
  		/*?*/reader.readInt();
  		int stringsOffset=reader.readInt();
  		int stylesOffset=reader.readInt();
  		
  		StringBlock block=new StringBlock();
  		block.m_stringOffsets=reader.readIntArray(stringCount);
  		if (styleOffsetCount!=0) {
  			block.m_styleOffsets=reader.readIntArray(styleOffsetCount);
  		}
  		{
  			int size=((stylesOffset==0)?chunkSize:stylesOffset)-stringsOffset;
  			if ((size%4)!=0) {
  				throw new IOException("String data size is not multiple of 4 ("+size+").");
  			}
  			block.m_strings=reader.readIntArray(size/4);
  		}
  		if (stylesOffset!=0) {
  			int size=(chunkSize-stylesOffset);
  			if ((size%4)!=0) {
  				throw new IOException("Style data size is not multiple of 4 ("+size+").");
  			}
  			block.m_styles=reader.readIntArray(size/4);
  		}
  
  		return block;	
  	}
  	
  	/**
  	 * Returns number of strings in block. 
  	 */
  	public int getCount() {
  		return m_stringOffsets!=null?
  			m_stringOffsets.length:
  			0;
  	}
  	
  	/**
  	 * Returns raw string (without any styling information) at specified index.
  	 */
  	public String getString(int index) {
  		if (index<0 ||
  			m_stringOffsets==null ||
  			index>=m_stringOffsets.length)
  		{
  			return null;
  		}
  		int offset=m_stringOffsets[index];
  		int length=getShort(m_strings,offset);
  		StringBuilder result=new StringBuilder(length);
  		for (;length!=0;length-=1) {
  			offset+=2;
  			result.append((char)getShort(m_strings,offset));
  		}
  		return result.toString();
  	}
  	
  	/**
  	 * Not yet implemented. 
  	 * 
  	 * Returns string with style information (if any).
  	 */
  	public CharSequence get(int index) {
  		return getString(index);
  	}
  
  	/**
  	 * Returns string with style tags (html-like). 
  	 */
  	public String getHTML(int index) {
  		String raw=getString(index);
  		if (raw==null) {
  			return raw;
  		}
  		int[] style=getStyle(index);
  		if (style==null) {
  			return raw;
  		}
  		StringBuilder html=new StringBuilder(raw.length()+32);
  		int offset=0;
  		while (true) {
  			int i=-1;
  			for (int j=0;j!=style.length;j+=3) {
  				if (style[j+1]==-1) {
  					continue;
  				}
  				if (i==-1 || style[i+1]>style[j+1]) {
  					i=j;
  				}
  			}
  			int start=((i!=-1)?style[i+1]:raw.length());
  			for (int j=0;j!=style.length;j+=3) {
  				int end=style[j+2];
  				if (end==-1 || end>=start) {
  					continue;
  				}
  				if (offset<=end) {
  					html.append(raw,offset,end+1);
  					offset=end+1;
  				}
  				style[j+2]=-1;
  				html.append('<');
  				html.append('/');
  				html.append(getString(style[j]));
  				html.append('>');
  			}
  			if (offset<start) {
  				html.append(raw,offset,start);
  				offset=start;
  			}
  			if (i==-1) {
  				break;
  			}
  			html.append('<');
  			html.append(getString(style[i]));
  			html.append('>');
  			style[i+1]=-1;
  		}
  		return html.toString();
  	}
  	
  	/**
  	 * Finds index of the string.
  	 * Returns -1 if the string was not found.
  	 */
  	public int find(String string) {
  		if (string==null) {
  			return -1;
  		}
  		for (int i=0;i!=m_stringOffsets.length;++i) {
  			int offset=m_stringOffsets[i];
  			int length=getShort(m_strings,offset);
  			if (length!=string.length()) {
  				continue;
  			}
  			int j=0;
  			for (;j!=length;++j) {
  				offset+=2;
  				if (string.charAt(j)!=getShort(m_strings,offset)) {
  					break;
  				}
  			}
  			if (j==length) {
  				return i;
  			}
  		}
  		return -1;
  	}
  	
  	///////////////////////////////////////////// implementation
  
  	public StringBlock() {
  	}
  	
  	/**
  	 * Returns style information - array of int triplets,
  	 * where in each triplet:
  	 * 	* first int is index of tag name ('b','i', etc.)
  	 * 	* second int is tag start index in string
  	 * 	* third int is tag end index in string
  	 */
  	public int[] getStyle(int index) {
  		if (m_styleOffsets==null || m_styles==null ||
  			index>=m_styleOffsets.length)
  		{
  			return null;
  		}
  		int offset=m_styleOffsets[index]/4;
  		int style[];
  		{
  			int count=0;
  			for (int i=offset;i<m_styles.length;++i) {
  				if (m_styles[i]==-1) {
  					break;
  				}
  				count+=1;
  			}
  			if (count==0 || (count%3)!=0) {
  				return null;
  			}
  			style=new int[count];
  		}
  		for (int i=offset,j=0;i<m_styles.length;) {
  			if (m_styles[i]==-1) {
  				break;
  			}
  			style[j++]=m_styles[i++];
  		}
  		return style;
  		
  	}
  	
  	public static final int getShort(int[] array,int offset) {
  		int value=array[offset/4];
  		if ((offset%4)/2==0) {
  			return (value & 0xFFFF);
  		} else {
  			return (value >>> 16);
  		}
  	}
  	
  	public int[] m_stringOffsets;
  	public int[] m_strings;
  	public int[] m_styleOffsets;
  	public int[] m_styles;
  
  	public static final int CHUNK_TYPE=0x001C0001;
  }
  