// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static byte[] getBytes(byte[] buffer, int offset) {
// 	byte[] b = new byte[buffer.length - offset];
// 	System.arraycopy(buffer, offset, b, 0, buffer.length - offset);
// 	return b;
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static int getInt(byte[] buffer, int offset, int length) {
// 	return getInt(getBytes(buffer, offset, length));
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static String getString(byte[] buffer, int offset, int length) {
// 	return getString(getBytes(buffer, offset, length));
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void write(byte[] data, OutputStream out) throws IOException {
// 	write(data, data.length, out);
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void writeInt(int data, int length, OutputStream out) throws IOException {
// 	out.write(getBytes(data, new byte[length]), 0, length);
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void writeString(String data, int length, OutputStream out) throws IOException {
// 	byte[] s = getBytes(data);
// 	byte[] b = new byte[length];
// 	System.arraycopy(s, 0, b, 0, s.length);
// 	out.write(b, 0, length);
// }


import static org.apache.commons.lang3.BooleanUtils.negate;
import static org.rr.mobi4java.ByteUtils.getBytes;
import static org.rr.mobi4java.ByteUtils.getInt;
import static org.rr.mobi4java.ByteUtils.getString;
import static org.rr.mobi4java.ByteUtils.write;
import static org.rr.mobi4java.ByteUtils.writeInt;
import static org.rr.mobi4java.ByteUtils.writeString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.output.TeeOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
package org.rr.mobi4java;




public class MobiContentHeader extends MobiContent {
	
	private static final int DEFAULT_HEADER_LENGTH = 264;
	
	/** Size of the extra bytes for the rest of mobi header*/
	private static final int MOBI_HEADER_REST = 16;

	public static enum COMPRESSION_CODE {
		NONE(1), PALM_DOC(2), HUFF_CDIC(17480);
		private final int type;
		
    private static Map<Integer, COMPRESSION_CODE> map = new HashMap<Integer, COMPRESSION_CODE>();
    
		static {
			for (COMPRESSION_CODE typeEnum : COMPRESSION_CODE.values()) {
				if(map.put(typeEnum.type, typeEnum) != null) {
					throw new IllegalArgumentException("Duplicate type " + typeEnum.type);
				}
			}
		}

		private COMPRESSION_CODE(final int type) {
			this.type = type;
		}
		
		public static COMPRESSION_CODE valueOf(int type) {
			return map.get(type);
		}

		public int getType() {
			return type;
		}
	}
	
	private int recordDataOffset;
	private int recordDataLength;
	
	private int compression;
	private int unused0;
	private int textLength;
	private int recordCount;
	private int recordSize;
	private int encryptionType;
	private int unused1;
	private int mobiType;
	private int textEncoding;
	private int uniqueID;
	private int fileVersion;
	private int orthographicIndex;
	private int inflectionIndex;
	private int indexNames;
	private int indexKeys;
	private int extraIndex0;
	private int extraIndex1;
	private int extraIndex2;
	private int extraIndex3;
	private int extraIndex4;
	private int extraIndex5;
	private int firstNonBookIndex;
	private int fullNameOffset;
	private int fullNameLength;
	private int locale;
	private int inputLanguage;
	private int outputLanguage;
	private int minVersion;
	private int firstImageIndex;
	private int huffmanRecordOffset;
	private int huffmanRecordCount;
	private int huffmanTableOffset;
	private int huffmanTableLength;
	private int exthFlags;
	private int firstContentRecordIndex = 1;
	private int lastContentRecordIndex = -1;
	private int fcisRecordIndex;
	private int fcisRecordCount;
	private int flisRecordIndex;
	private int srcsRecordIndex = -1;
	private int srcsRecordCount;
	private int flisRecordCount;
	private int extraRecordDataFlags;
	private int indxRecordIndex = -1;
	private int fragmentRecordIndex = -1;
	private int skeletonRecordIndex = -1;
	private int datpRecordIndex = -1;
	private int guideIndex = -1;
	
	private EXTHHeader exthHeader;
	private byte[] remainder;
	// end of useful data
	
	private MobiContentHeader(byte[] content, long recordDataOffset, long recordDataLength) {
		super(getBytes(content, (int) recordDataOffset, (int) recordDataLength), CONTENT_TYPE.HEADER);
		this.recordDataOffset = (int) recordDataOffset;
		this.recordDataLength = (int) recordDataLength;
	}
	
	static MobiContentHeader readMobiHeader(byte[] content, long recordDataOffset, long recordDataLength) throws IOException {
		return new MobiContentHeader(content, recordDataOffset, recordDataLength).readMobiHeader();
	}
	
	private MobiContentHeader readMobiHeader() throws IOException {
		// first 16 bytes of the PalmDOC Header followed by the MOBI header
		compression = getInt(content, 0, 2);
		unused0 = getInt(content, 2, 2);
		textLength = getInt(content, 4, 4);
		recordCount = getInt(content, 8, 2);
		recordSize = getInt(content, 10, 2);
		encryptionType = getInt(content, 12, 2);
		unused1 = getInt(content, 14, 2);
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static byte[] getBytes(byte[] buffer, int offset) {
// 	byte[] b = new byte[buffer.length - offset];
// 	System.arraycopy(buffer, offset, b, 0, buffer.length - offset);
// 	return b;
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static int getInt(byte[] buffer, int offset, int length) {
// 	return getInt(getBytes(buffer, offset, length));
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static String getString(byte[] buffer, int offset, int length) {
// 	return getString(getBytes(buffer, offset, length));
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void write(byte[] data, OutputStream out) throws IOException {
// 	write(data, data.length, out);
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void writeInt(int data, int length, OutputStream out) throws IOException {
// 	out.write(getBytes(data, new byte[length]), 0, length);
// }
// 
// Path: src/main/java/org/rr/mobi4java/ByteUtils.java
// public static void writeString(String data, int length, OutputStream out) throws IOException {
// 	byte[] s = getBytes(data);
// 	byte[] b = new byte[length];
// 	System.arraycopy(s, 0, b, 0, s.length);
// 	out.write(b, 0, length);
// }


// Path: src/main/java/org/rr/mobi4java/MobiContentHeader.java
import static org.apache.commons.lang3.BooleanUtils.negate;
import static org.rr.mobi4java.ByteUtils.getBytes;
import static org.rr.mobi4java.ByteUtils.getInt;
import static org.rr.mobi4java.ByteUtils.getString;
import static org.rr.mobi4java.ByteUtils.write;
import static org.rr.mobi4java.ByteUtils.writeInt;
import static org.rr.mobi4java.ByteUtils.writeString;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.output.TeeOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

package org.rr.mobi4java;




public class MobiContentHeader extends MobiContent {
	
	private static final int DEFAULT_HEADER_LENGTH = 264;
	
	/** Size of the extra bytes for the rest of mobi header*/
	private static final int MOBI_HEADER_REST = 16;

	public static enum COMPRESSION_CODE {
		NONE(1), PALM_DOC(2), HUFF_CDIC(17480);
		private final int type;
		
    private static Map<Integer, COMPRESSION_CODE> map = new HashMap<Integer, COMPRESSION_CODE>();
    
		static {
			for (COMPRESSION_CODE typeEnum : COMPRESSION_CODE.values()) {
				if(map.put(typeEnum.type, typeEnum) != null) {
					throw new IllegalArgumentException("Duplicate type " + typeEnum.type);
				}
			}
		}

		private COMPRESSION_CODE(final int type) {
			this.type = type;
		}
		
		public static COMPRESSION_CODE valueOf(int type) {
			return map.get(type);
		}

		public int getType() {
			return type;
		}
	}
	
	private int recordDataOffset;
	private int recordDataLength;
	
	private int compression;
	private int unused0;
	private int textLength;
	private int recordCount;
	private int recordSize;
	private int encryptionType;
	private int unused1;
	private int mobiType;
	private int textEncoding;
	private int uniqueID;
	private int fileVersion;
	private int orthographicIndex;
	private int inflectionIndex;
	private int indexNames;
	private int indexKeys;
	private int extraIndex0;
	private int extraIndex1;
	private int extraIndex2;
	private int extraIndex3;
	private int extraIndex4;
	private int extraIndex5;
	private int firstNonBookIndex;
	private int fullNameOffset;
	private int fullNameLength;
	private int locale;
	private int inputLanguage;
	private int outputLanguage;
	private int minVersion;
	private int firstImageIndex;
	private int huffmanRecordOffset;
	private int huffmanRecordCount;
	private int huffmanTableOffset;
	private int huffmanTableLength;
	private int exthFlags;
	private int firstContentRecordIndex = 1;
	private int lastContentRecordIndex = -1;
	private int fcisRecordIndex;
	private int fcisRecordCount;
	private int flisRecordIndex;
	private int srcsRecordIndex = -1;
	private int srcsRecordCount;
	private int flisRecordCount;
	private int extraRecordDataFlags;
	private int indxRecordIndex = -1;
	private int fragmentRecordIndex = -1;
	private int skeletonRecordIndex = -1;
	private int datpRecordIndex = -1;
	private int guideIndex = -1;
	
	private EXTHHeader exthHeader;
	private byte[] remainder;
	// end of useful data
	
	private MobiContentHeader(byte[] content, long recordDataOffset, long recordDataLength) {
		super(getBytes(content, (int) recordDataOffset, (int) recordDataLength), CONTENT_TYPE.HEADER);
		this.recordDataOffset = (int) recordDataOffset;
		this.recordDataLength = (int) recordDataLength;
	}
	
	static MobiContentHeader readMobiHeader(byte[] content, long recordDataOffset, long recordDataLength) throws IOException {
		return new MobiContentHeader(content, recordDataOffset, recordDataLength).readMobiHeader();
	}
	
	private MobiContentHeader readMobiHeader() throws IOException {
		// first 16 bytes of the PalmDOC Header followed by the MOBI header
		compression = getInt(content, 0, 2);
		unused0 = getInt(content, 2, 2);
		textLength = getInt(content, 4, 4);
		recordCount = getInt(content, 8, 2);
		recordSize = getInt(content, 10, 2);
		encryptionType = getInt(content, 12, 2);
		unused1 = getInt(content, 14, 2);
		String identifier = getString(content, 16, 4);